1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * SPDX-License-Identifier: MIT
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright © 2018 Intel Corporation
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <linux/prime_numbers.h>
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include "gem/i915_gem_pm.h"
10*4882a593Smuzhiyun #include "gt/intel_engine_heartbeat.h"
11*4882a593Smuzhiyun #include "gt/intel_reset.h"
12*4882a593Smuzhiyun #include "gt/selftest_engine_heartbeat.h"
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #include "i915_selftest.h"
15*4882a593Smuzhiyun #include "selftests/i915_random.h"
16*4882a593Smuzhiyun #include "selftests/igt_flush_test.h"
17*4882a593Smuzhiyun #include "selftests/igt_live_test.h"
18*4882a593Smuzhiyun #include "selftests/igt_spinner.h"
19*4882a593Smuzhiyun #include "selftests/lib_sw_fence.h"
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #include "gem/selftests/igt_gem_utils.h"
22*4882a593Smuzhiyun #include "gem/selftests/mock_context.h"
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #define CS_GPR(engine, n) ((engine)->mmio_base + 0x600 + (n) * 4)
25*4882a593Smuzhiyun #define NUM_GPR 16
26*4882a593Smuzhiyun #define NUM_GPR_DW (NUM_GPR * 2) /* each GPR is 2 dwords */
27*4882a593Smuzhiyun
create_scratch(struct intel_gt * gt)28*4882a593Smuzhiyun static struct i915_vma *create_scratch(struct intel_gt *gt)
29*4882a593Smuzhiyun {
30*4882a593Smuzhiyun struct drm_i915_gem_object *obj;
31*4882a593Smuzhiyun struct i915_vma *vma;
32*4882a593Smuzhiyun int err;
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun obj = i915_gem_object_create_internal(gt->i915, PAGE_SIZE);
35*4882a593Smuzhiyun if (IS_ERR(obj))
36*4882a593Smuzhiyun return ERR_CAST(obj);
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun i915_gem_object_set_cache_coherency(obj, I915_CACHING_CACHED);
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun vma = i915_vma_instance(obj, >->ggtt->vm, NULL);
41*4882a593Smuzhiyun if (IS_ERR(vma)) {
42*4882a593Smuzhiyun i915_gem_object_put(obj);
43*4882a593Smuzhiyun return vma;
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL);
47*4882a593Smuzhiyun if (err) {
48*4882a593Smuzhiyun i915_gem_object_put(obj);
49*4882a593Smuzhiyun return ERR_PTR(err);
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun return vma;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun
is_active(struct i915_request * rq)55*4882a593Smuzhiyun static bool is_active(struct i915_request *rq)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun if (i915_request_is_active(rq))
58*4882a593Smuzhiyun return true;
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun if (i915_request_on_hold(rq))
61*4882a593Smuzhiyun return true;
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun if (i915_request_has_initial_breadcrumb(rq) && i915_request_started(rq))
64*4882a593Smuzhiyun return true;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun return false;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun
wait_for_submit(struct intel_engine_cs * engine,struct i915_request * rq,unsigned long timeout)69*4882a593Smuzhiyun static int wait_for_submit(struct intel_engine_cs *engine,
70*4882a593Smuzhiyun struct i915_request *rq,
71*4882a593Smuzhiyun unsigned long timeout)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun timeout += jiffies;
74*4882a593Smuzhiyun do {
75*4882a593Smuzhiyun bool done = time_after(jiffies, timeout);
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun if (i915_request_completed(rq)) /* that was quick! */
78*4882a593Smuzhiyun return 0;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun /* Wait until the HW has acknowleged the submission (or err) */
81*4882a593Smuzhiyun intel_engine_flush_submission(engine);
82*4882a593Smuzhiyun if (!READ_ONCE(engine->execlists.pending[0]) && is_active(rq))
83*4882a593Smuzhiyun return 0;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun if (done)
86*4882a593Smuzhiyun return -ETIME;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun cond_resched();
89*4882a593Smuzhiyun } while (1);
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
wait_for_reset(struct intel_engine_cs * engine,struct i915_request * rq,unsigned long timeout)92*4882a593Smuzhiyun static int wait_for_reset(struct intel_engine_cs *engine,
93*4882a593Smuzhiyun struct i915_request *rq,
94*4882a593Smuzhiyun unsigned long timeout)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun timeout += jiffies;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun do {
99*4882a593Smuzhiyun cond_resched();
100*4882a593Smuzhiyun intel_engine_flush_submission(engine);
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun if (READ_ONCE(engine->execlists.pending[0]))
103*4882a593Smuzhiyun continue;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun if (i915_request_completed(rq))
106*4882a593Smuzhiyun break;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun if (READ_ONCE(rq->fence.error))
109*4882a593Smuzhiyun break;
110*4882a593Smuzhiyun } while (time_before(jiffies, timeout));
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun flush_scheduled_work();
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun if (rq->fence.error != -EIO) {
115*4882a593Smuzhiyun pr_err("%s: hanging request %llx:%lld not reset\n",
116*4882a593Smuzhiyun engine->name,
117*4882a593Smuzhiyun rq->fence.context,
118*4882a593Smuzhiyun rq->fence.seqno);
119*4882a593Smuzhiyun return -EINVAL;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun /* Give the request a jiffie to complete after flushing the worker */
123*4882a593Smuzhiyun if (i915_request_wait(rq, 0,
124*4882a593Smuzhiyun max(0l, (long)(timeout - jiffies)) + 1) < 0) {
125*4882a593Smuzhiyun pr_err("%s: hanging request %llx:%lld did not complete\n",
126*4882a593Smuzhiyun engine->name,
127*4882a593Smuzhiyun rq->fence.context,
128*4882a593Smuzhiyun rq->fence.seqno);
129*4882a593Smuzhiyun return -ETIME;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun return 0;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun
live_sanitycheck(void * arg)135*4882a593Smuzhiyun static int live_sanitycheck(void *arg)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun struct intel_gt *gt = arg;
138*4882a593Smuzhiyun struct intel_engine_cs *engine;
139*4882a593Smuzhiyun enum intel_engine_id id;
140*4882a593Smuzhiyun struct igt_spinner spin;
141*4882a593Smuzhiyun int err = 0;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun if (!HAS_LOGICAL_RING_CONTEXTS(gt->i915))
144*4882a593Smuzhiyun return 0;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun if (igt_spinner_init(&spin, gt))
147*4882a593Smuzhiyun return -ENOMEM;
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
150*4882a593Smuzhiyun struct intel_context *ce;
151*4882a593Smuzhiyun struct i915_request *rq;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun ce = intel_context_create(engine);
154*4882a593Smuzhiyun if (IS_ERR(ce)) {
155*4882a593Smuzhiyun err = PTR_ERR(ce);
156*4882a593Smuzhiyun break;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun rq = igt_spinner_create_request(&spin, ce, MI_NOOP);
160*4882a593Smuzhiyun if (IS_ERR(rq)) {
161*4882a593Smuzhiyun err = PTR_ERR(rq);
162*4882a593Smuzhiyun goto out_ctx;
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun i915_request_add(rq);
166*4882a593Smuzhiyun if (!igt_wait_for_spinner(&spin, rq)) {
167*4882a593Smuzhiyun GEM_TRACE("spinner failed to start\n");
168*4882a593Smuzhiyun GEM_TRACE_DUMP();
169*4882a593Smuzhiyun intel_gt_set_wedged(gt);
170*4882a593Smuzhiyun err = -EIO;
171*4882a593Smuzhiyun goto out_ctx;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun igt_spinner_end(&spin);
175*4882a593Smuzhiyun if (igt_flush_test(gt->i915)) {
176*4882a593Smuzhiyun err = -EIO;
177*4882a593Smuzhiyun goto out_ctx;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun out_ctx:
181*4882a593Smuzhiyun intel_context_put(ce);
182*4882a593Smuzhiyun if (err)
183*4882a593Smuzhiyun break;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun igt_spinner_fini(&spin);
187*4882a593Smuzhiyun return err;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
live_unlite_restore(struct intel_gt * gt,int prio)190*4882a593Smuzhiyun static int live_unlite_restore(struct intel_gt *gt, int prio)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun struct intel_engine_cs *engine;
193*4882a593Smuzhiyun enum intel_engine_id id;
194*4882a593Smuzhiyun struct igt_spinner spin;
195*4882a593Smuzhiyun int err = -ENOMEM;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun /*
198*4882a593Smuzhiyun * Check that we can correctly context switch between 2 instances
199*4882a593Smuzhiyun * on the same engine from the same parent context.
200*4882a593Smuzhiyun */
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun if (igt_spinner_init(&spin, gt))
203*4882a593Smuzhiyun return err;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun err = 0;
206*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
207*4882a593Smuzhiyun struct intel_context *ce[2] = {};
208*4882a593Smuzhiyun struct i915_request *rq[2];
209*4882a593Smuzhiyun struct igt_live_test t;
210*4882a593Smuzhiyun int n;
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun if (prio && !intel_engine_has_preemption(engine))
213*4882a593Smuzhiyun continue;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun if (!intel_engine_can_store_dword(engine))
216*4882a593Smuzhiyun continue;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun if (igt_live_test_begin(&t, gt->i915, __func__, engine->name)) {
219*4882a593Smuzhiyun err = -EIO;
220*4882a593Smuzhiyun break;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun st_engine_heartbeat_disable(engine);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun for (n = 0; n < ARRAY_SIZE(ce); n++) {
225*4882a593Smuzhiyun struct intel_context *tmp;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun tmp = intel_context_create(engine);
228*4882a593Smuzhiyun if (IS_ERR(tmp)) {
229*4882a593Smuzhiyun err = PTR_ERR(tmp);
230*4882a593Smuzhiyun goto err_ce;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun err = intel_context_pin(tmp);
234*4882a593Smuzhiyun if (err) {
235*4882a593Smuzhiyun intel_context_put(tmp);
236*4882a593Smuzhiyun goto err_ce;
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun /*
240*4882a593Smuzhiyun * Setup the pair of contexts such that if we
241*4882a593Smuzhiyun * lite-restore using the RING_TAIL from ce[1] it
242*4882a593Smuzhiyun * will execute garbage from ce[0]->ring.
243*4882a593Smuzhiyun */
244*4882a593Smuzhiyun memset(tmp->ring->vaddr,
245*4882a593Smuzhiyun POISON_INUSE, /* IPEHR: 0x5a5a5a5a [hung!] */
246*4882a593Smuzhiyun tmp->ring->vma->size);
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun ce[n] = tmp;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun GEM_BUG_ON(!ce[1]->ring->size);
251*4882a593Smuzhiyun intel_ring_reset(ce[1]->ring, ce[1]->ring->size / 2);
252*4882a593Smuzhiyun __execlists_update_reg_state(ce[1], engine, ce[1]->ring->head);
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun rq[0] = igt_spinner_create_request(&spin, ce[0], MI_ARB_CHECK);
255*4882a593Smuzhiyun if (IS_ERR(rq[0])) {
256*4882a593Smuzhiyun err = PTR_ERR(rq[0]);
257*4882a593Smuzhiyun goto err_ce;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun i915_request_get(rq[0]);
261*4882a593Smuzhiyun i915_request_add(rq[0]);
262*4882a593Smuzhiyun GEM_BUG_ON(rq[0]->postfix > ce[1]->ring->emit);
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun if (!igt_wait_for_spinner(&spin, rq[0])) {
265*4882a593Smuzhiyun i915_request_put(rq[0]);
266*4882a593Smuzhiyun goto err_ce;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun rq[1] = i915_request_create(ce[1]);
270*4882a593Smuzhiyun if (IS_ERR(rq[1])) {
271*4882a593Smuzhiyun err = PTR_ERR(rq[1]);
272*4882a593Smuzhiyun i915_request_put(rq[0]);
273*4882a593Smuzhiyun goto err_ce;
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun if (!prio) {
277*4882a593Smuzhiyun /*
278*4882a593Smuzhiyun * Ensure we do the switch to ce[1] on completion.
279*4882a593Smuzhiyun *
280*4882a593Smuzhiyun * rq[0] is already submitted, so this should reduce
281*4882a593Smuzhiyun * to a no-op (a wait on a request on the same engine
282*4882a593Smuzhiyun * uses the submit fence, not the completion fence),
283*4882a593Smuzhiyun * but it will install a dependency on rq[1] for rq[0]
284*4882a593Smuzhiyun * that will prevent the pair being reordered by
285*4882a593Smuzhiyun * timeslicing.
286*4882a593Smuzhiyun */
287*4882a593Smuzhiyun i915_request_await_dma_fence(rq[1], &rq[0]->fence);
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun i915_request_get(rq[1]);
291*4882a593Smuzhiyun i915_request_add(rq[1]);
292*4882a593Smuzhiyun GEM_BUG_ON(rq[1]->postfix <= rq[0]->postfix);
293*4882a593Smuzhiyun i915_request_put(rq[0]);
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun if (prio) {
296*4882a593Smuzhiyun struct i915_sched_attr attr = {
297*4882a593Smuzhiyun .priority = prio,
298*4882a593Smuzhiyun };
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun /* Alternatively preempt the spinner with ce[1] */
301*4882a593Smuzhiyun engine->schedule(rq[1], &attr);
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun /* And switch back to ce[0] for good measure */
305*4882a593Smuzhiyun rq[0] = i915_request_create(ce[0]);
306*4882a593Smuzhiyun if (IS_ERR(rq[0])) {
307*4882a593Smuzhiyun err = PTR_ERR(rq[0]);
308*4882a593Smuzhiyun i915_request_put(rq[1]);
309*4882a593Smuzhiyun goto err_ce;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun i915_request_await_dma_fence(rq[0], &rq[1]->fence);
313*4882a593Smuzhiyun i915_request_get(rq[0]);
314*4882a593Smuzhiyun i915_request_add(rq[0]);
315*4882a593Smuzhiyun GEM_BUG_ON(rq[0]->postfix > rq[1]->postfix);
316*4882a593Smuzhiyun i915_request_put(rq[1]);
317*4882a593Smuzhiyun i915_request_put(rq[0]);
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun err_ce:
320*4882a593Smuzhiyun intel_engine_flush_submission(engine);
321*4882a593Smuzhiyun igt_spinner_end(&spin);
322*4882a593Smuzhiyun for (n = 0; n < ARRAY_SIZE(ce); n++) {
323*4882a593Smuzhiyun if (IS_ERR_OR_NULL(ce[n]))
324*4882a593Smuzhiyun break;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun intel_context_unpin(ce[n]);
327*4882a593Smuzhiyun intel_context_put(ce[n]);
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun st_engine_heartbeat_enable(engine);
331*4882a593Smuzhiyun if (igt_live_test_end(&t))
332*4882a593Smuzhiyun err = -EIO;
333*4882a593Smuzhiyun if (err)
334*4882a593Smuzhiyun break;
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun igt_spinner_fini(&spin);
338*4882a593Smuzhiyun return err;
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun
live_unlite_switch(void * arg)341*4882a593Smuzhiyun static int live_unlite_switch(void *arg)
342*4882a593Smuzhiyun {
343*4882a593Smuzhiyun return live_unlite_restore(arg, 0);
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
live_unlite_preempt(void * arg)346*4882a593Smuzhiyun static int live_unlite_preempt(void *arg)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun return live_unlite_restore(arg, I915_USER_PRIORITY(I915_PRIORITY_MAX));
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun
live_unlite_ring(void * arg)351*4882a593Smuzhiyun static int live_unlite_ring(void *arg)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun struct intel_gt *gt = arg;
354*4882a593Smuzhiyun struct intel_engine_cs *engine;
355*4882a593Smuzhiyun struct igt_spinner spin;
356*4882a593Smuzhiyun enum intel_engine_id id;
357*4882a593Smuzhiyun int err = 0;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun /*
360*4882a593Smuzhiyun * Setup a preemption event that will cause almost the entire ring
361*4882a593Smuzhiyun * to be unwound, potentially fooling our intel_ring_direction()
362*4882a593Smuzhiyun * into emitting a forward lite-restore instead of the rollback.
363*4882a593Smuzhiyun */
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun if (igt_spinner_init(&spin, gt))
366*4882a593Smuzhiyun return -ENOMEM;
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
369*4882a593Smuzhiyun struct intel_context *ce[2] = {};
370*4882a593Smuzhiyun struct i915_request *rq;
371*4882a593Smuzhiyun struct igt_live_test t;
372*4882a593Smuzhiyun int n;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun if (!intel_engine_has_preemption(engine))
375*4882a593Smuzhiyun continue;
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun if (!intel_engine_can_store_dword(engine))
378*4882a593Smuzhiyun continue;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun if (igt_live_test_begin(&t, gt->i915, __func__, engine->name)) {
381*4882a593Smuzhiyun err = -EIO;
382*4882a593Smuzhiyun break;
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun st_engine_heartbeat_disable(engine);
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun for (n = 0; n < ARRAY_SIZE(ce); n++) {
387*4882a593Smuzhiyun struct intel_context *tmp;
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun tmp = intel_context_create(engine);
390*4882a593Smuzhiyun if (IS_ERR(tmp)) {
391*4882a593Smuzhiyun err = PTR_ERR(tmp);
392*4882a593Smuzhiyun goto err_ce;
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun err = intel_context_pin(tmp);
396*4882a593Smuzhiyun if (err) {
397*4882a593Smuzhiyun intel_context_put(tmp);
398*4882a593Smuzhiyun goto err_ce;
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun memset32(tmp->ring->vaddr,
402*4882a593Smuzhiyun 0xdeadbeef, /* trigger a hang if executed */
403*4882a593Smuzhiyun tmp->ring->vma->size / sizeof(u32));
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun ce[n] = tmp;
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun /* Create max prio spinner, followed by N low prio nops */
409*4882a593Smuzhiyun rq = igt_spinner_create_request(&spin, ce[0], MI_ARB_CHECK);
410*4882a593Smuzhiyun if (IS_ERR(rq)) {
411*4882a593Smuzhiyun err = PTR_ERR(rq);
412*4882a593Smuzhiyun goto err_ce;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun i915_request_get(rq);
416*4882a593Smuzhiyun rq->sched.attr.priority = I915_PRIORITY_BARRIER;
417*4882a593Smuzhiyun i915_request_add(rq);
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun if (!igt_wait_for_spinner(&spin, rq)) {
420*4882a593Smuzhiyun intel_gt_set_wedged(gt);
421*4882a593Smuzhiyun i915_request_put(rq);
422*4882a593Smuzhiyun err = -ETIME;
423*4882a593Smuzhiyun goto err_ce;
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun /* Fill the ring, until we will cause a wrap */
427*4882a593Smuzhiyun n = 0;
428*4882a593Smuzhiyun while (intel_ring_direction(ce[0]->ring,
429*4882a593Smuzhiyun rq->wa_tail,
430*4882a593Smuzhiyun ce[0]->ring->tail) <= 0) {
431*4882a593Smuzhiyun struct i915_request *tmp;
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun tmp = intel_context_create_request(ce[0]);
434*4882a593Smuzhiyun if (IS_ERR(tmp)) {
435*4882a593Smuzhiyun err = PTR_ERR(tmp);
436*4882a593Smuzhiyun i915_request_put(rq);
437*4882a593Smuzhiyun goto err_ce;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun i915_request_add(tmp);
441*4882a593Smuzhiyun intel_engine_flush_submission(engine);
442*4882a593Smuzhiyun n++;
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun intel_engine_flush_submission(engine);
445*4882a593Smuzhiyun pr_debug("%s: Filled ring with %d nop tails {size:%x, tail:%x, emit:%x, rq.tail:%x}\n",
446*4882a593Smuzhiyun engine->name, n,
447*4882a593Smuzhiyun ce[0]->ring->size,
448*4882a593Smuzhiyun ce[0]->ring->tail,
449*4882a593Smuzhiyun ce[0]->ring->emit,
450*4882a593Smuzhiyun rq->tail);
451*4882a593Smuzhiyun GEM_BUG_ON(intel_ring_direction(ce[0]->ring,
452*4882a593Smuzhiyun rq->tail,
453*4882a593Smuzhiyun ce[0]->ring->tail) <= 0);
454*4882a593Smuzhiyun i915_request_put(rq);
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun /* Create a second ring to preempt the first ring after rq[0] */
457*4882a593Smuzhiyun rq = intel_context_create_request(ce[1]);
458*4882a593Smuzhiyun if (IS_ERR(rq)) {
459*4882a593Smuzhiyun err = PTR_ERR(rq);
460*4882a593Smuzhiyun goto err_ce;
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun rq->sched.attr.priority = I915_PRIORITY_BARRIER;
464*4882a593Smuzhiyun i915_request_get(rq);
465*4882a593Smuzhiyun i915_request_add(rq);
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun err = wait_for_submit(engine, rq, HZ / 2);
468*4882a593Smuzhiyun i915_request_put(rq);
469*4882a593Smuzhiyun if (err) {
470*4882a593Smuzhiyun pr_err("%s: preemption request was not submitted\n",
471*4882a593Smuzhiyun engine->name);
472*4882a593Smuzhiyun err = -ETIME;
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun pr_debug("%s: ring[0]:{ tail:%x, emit:%x }, ring[1]:{ tail:%x, emit:%x }\n",
476*4882a593Smuzhiyun engine->name,
477*4882a593Smuzhiyun ce[0]->ring->tail, ce[0]->ring->emit,
478*4882a593Smuzhiyun ce[1]->ring->tail, ce[1]->ring->emit);
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun err_ce:
481*4882a593Smuzhiyun intel_engine_flush_submission(engine);
482*4882a593Smuzhiyun igt_spinner_end(&spin);
483*4882a593Smuzhiyun for (n = 0; n < ARRAY_SIZE(ce); n++) {
484*4882a593Smuzhiyun if (IS_ERR_OR_NULL(ce[n]))
485*4882a593Smuzhiyun break;
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun intel_context_unpin(ce[n]);
488*4882a593Smuzhiyun intel_context_put(ce[n]);
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun st_engine_heartbeat_enable(engine);
491*4882a593Smuzhiyun if (igt_live_test_end(&t))
492*4882a593Smuzhiyun err = -EIO;
493*4882a593Smuzhiyun if (err)
494*4882a593Smuzhiyun break;
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun igt_spinner_fini(&spin);
498*4882a593Smuzhiyun return err;
499*4882a593Smuzhiyun }
500*4882a593Smuzhiyun
live_pin_rewind(void * arg)501*4882a593Smuzhiyun static int live_pin_rewind(void *arg)
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun struct intel_gt *gt = arg;
504*4882a593Smuzhiyun struct intel_engine_cs *engine;
505*4882a593Smuzhiyun enum intel_engine_id id;
506*4882a593Smuzhiyun int err = 0;
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun /*
509*4882a593Smuzhiyun * We have to be careful not to trust intel_ring too much, for example
510*4882a593Smuzhiyun * ring->head is updated upon retire which is out of sync with pinning
511*4882a593Smuzhiyun * the context. Thus we cannot use ring->head to set CTX_RING_HEAD,
512*4882a593Smuzhiyun * or else we risk writing an older, stale value.
513*4882a593Smuzhiyun *
514*4882a593Smuzhiyun * To simulate this, let's apply a bit of deliberate sabotague.
515*4882a593Smuzhiyun */
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
518*4882a593Smuzhiyun struct intel_context *ce;
519*4882a593Smuzhiyun struct i915_request *rq;
520*4882a593Smuzhiyun struct intel_ring *ring;
521*4882a593Smuzhiyun struct igt_live_test t;
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun if (igt_live_test_begin(&t, gt->i915, __func__, engine->name)) {
524*4882a593Smuzhiyun err = -EIO;
525*4882a593Smuzhiyun break;
526*4882a593Smuzhiyun }
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun ce = intel_context_create(engine);
529*4882a593Smuzhiyun if (IS_ERR(ce)) {
530*4882a593Smuzhiyun err = PTR_ERR(ce);
531*4882a593Smuzhiyun break;
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun err = intel_context_pin(ce);
535*4882a593Smuzhiyun if (err) {
536*4882a593Smuzhiyun intel_context_put(ce);
537*4882a593Smuzhiyun break;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun /* Keep the context awake while we play games */
541*4882a593Smuzhiyun err = i915_active_acquire(&ce->active);
542*4882a593Smuzhiyun if (err) {
543*4882a593Smuzhiyun intel_context_unpin(ce);
544*4882a593Smuzhiyun intel_context_put(ce);
545*4882a593Smuzhiyun break;
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun ring = ce->ring;
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun /* Poison the ring, and offset the next request from HEAD */
550*4882a593Smuzhiyun memset32(ring->vaddr, STACK_MAGIC, ring->size / sizeof(u32));
551*4882a593Smuzhiyun ring->emit = ring->size / 2;
552*4882a593Smuzhiyun ring->tail = ring->emit;
553*4882a593Smuzhiyun GEM_BUG_ON(ring->head);
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun intel_context_unpin(ce);
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun /* Submit a simple nop request */
558*4882a593Smuzhiyun GEM_BUG_ON(intel_context_is_pinned(ce));
559*4882a593Smuzhiyun rq = intel_context_create_request(ce);
560*4882a593Smuzhiyun i915_active_release(&ce->active); /* e.g. async retire */
561*4882a593Smuzhiyun intel_context_put(ce);
562*4882a593Smuzhiyun if (IS_ERR(rq)) {
563*4882a593Smuzhiyun err = PTR_ERR(rq);
564*4882a593Smuzhiyun break;
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun GEM_BUG_ON(!rq->head);
567*4882a593Smuzhiyun i915_request_add(rq);
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun /* Expect not to hang! */
570*4882a593Smuzhiyun if (igt_live_test_end(&t)) {
571*4882a593Smuzhiyun err = -EIO;
572*4882a593Smuzhiyun break;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun }
575*4882a593Smuzhiyun
576*4882a593Smuzhiyun return err;
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun
live_hold_reset(void * arg)579*4882a593Smuzhiyun static int live_hold_reset(void *arg)
580*4882a593Smuzhiyun {
581*4882a593Smuzhiyun struct intel_gt *gt = arg;
582*4882a593Smuzhiyun struct intel_engine_cs *engine;
583*4882a593Smuzhiyun enum intel_engine_id id;
584*4882a593Smuzhiyun struct igt_spinner spin;
585*4882a593Smuzhiyun int err = 0;
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun /*
588*4882a593Smuzhiyun * In order to support offline error capture for fast preempt reset,
589*4882a593Smuzhiyun * we need to decouple the guilty request and ensure that it and its
590*4882a593Smuzhiyun * descendents are not executed while the capture is in progress.
591*4882a593Smuzhiyun */
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun if (!intel_has_reset_engine(gt))
594*4882a593Smuzhiyun return 0;
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun if (igt_spinner_init(&spin, gt))
597*4882a593Smuzhiyun return -ENOMEM;
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
600*4882a593Smuzhiyun struct intel_context *ce;
601*4882a593Smuzhiyun struct i915_request *rq;
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun ce = intel_context_create(engine);
604*4882a593Smuzhiyun if (IS_ERR(ce)) {
605*4882a593Smuzhiyun err = PTR_ERR(ce);
606*4882a593Smuzhiyun break;
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun st_engine_heartbeat_disable(engine);
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun rq = igt_spinner_create_request(&spin, ce, MI_ARB_CHECK);
612*4882a593Smuzhiyun if (IS_ERR(rq)) {
613*4882a593Smuzhiyun err = PTR_ERR(rq);
614*4882a593Smuzhiyun goto out;
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun i915_request_add(rq);
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun if (!igt_wait_for_spinner(&spin, rq)) {
619*4882a593Smuzhiyun intel_gt_set_wedged(gt);
620*4882a593Smuzhiyun err = -ETIME;
621*4882a593Smuzhiyun goto out;
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun /* We have our request executing, now remove it and reset */
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun if (test_and_set_bit(I915_RESET_ENGINE + id,
627*4882a593Smuzhiyun >->reset.flags)) {
628*4882a593Smuzhiyun intel_gt_set_wedged(gt);
629*4882a593Smuzhiyun err = -EBUSY;
630*4882a593Smuzhiyun goto out;
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun tasklet_disable(&engine->execlists.tasklet);
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun engine->execlists.tasklet.func(engine->execlists.tasklet.data);
635*4882a593Smuzhiyun GEM_BUG_ON(execlists_active(&engine->execlists) != rq);
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun i915_request_get(rq);
638*4882a593Smuzhiyun execlists_hold(engine, rq);
639*4882a593Smuzhiyun GEM_BUG_ON(!i915_request_on_hold(rq));
640*4882a593Smuzhiyun
641*4882a593Smuzhiyun intel_engine_reset(engine, NULL);
642*4882a593Smuzhiyun GEM_BUG_ON(rq->fence.error != -EIO);
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun tasklet_enable(&engine->execlists.tasklet);
645*4882a593Smuzhiyun clear_and_wake_up_bit(I915_RESET_ENGINE + id,
646*4882a593Smuzhiyun >->reset.flags);
647*4882a593Smuzhiyun
648*4882a593Smuzhiyun /* Check that we do not resubmit the held request */
649*4882a593Smuzhiyun if (!i915_request_wait(rq, 0, HZ / 5)) {
650*4882a593Smuzhiyun pr_err("%s: on hold request completed!\n",
651*4882a593Smuzhiyun engine->name);
652*4882a593Smuzhiyun i915_request_put(rq);
653*4882a593Smuzhiyun err = -EIO;
654*4882a593Smuzhiyun goto out;
655*4882a593Smuzhiyun }
656*4882a593Smuzhiyun GEM_BUG_ON(!i915_request_on_hold(rq));
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun /* But is resubmitted on release */
659*4882a593Smuzhiyun execlists_unhold(engine, rq);
660*4882a593Smuzhiyun if (i915_request_wait(rq, 0, HZ / 5) < 0) {
661*4882a593Smuzhiyun pr_err("%s: held request did not complete!\n",
662*4882a593Smuzhiyun engine->name);
663*4882a593Smuzhiyun intel_gt_set_wedged(gt);
664*4882a593Smuzhiyun err = -ETIME;
665*4882a593Smuzhiyun }
666*4882a593Smuzhiyun i915_request_put(rq);
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun out:
669*4882a593Smuzhiyun st_engine_heartbeat_enable(engine);
670*4882a593Smuzhiyun intel_context_put(ce);
671*4882a593Smuzhiyun if (err)
672*4882a593Smuzhiyun break;
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun igt_spinner_fini(&spin);
676*4882a593Smuzhiyun return err;
677*4882a593Smuzhiyun }
678*4882a593Smuzhiyun
error_repr(int err)679*4882a593Smuzhiyun static const char *error_repr(int err)
680*4882a593Smuzhiyun {
681*4882a593Smuzhiyun return err ? "bad" : "good";
682*4882a593Smuzhiyun }
683*4882a593Smuzhiyun
live_error_interrupt(void * arg)684*4882a593Smuzhiyun static int live_error_interrupt(void *arg)
685*4882a593Smuzhiyun {
686*4882a593Smuzhiyun static const struct error_phase {
687*4882a593Smuzhiyun enum { GOOD = 0, BAD = -EIO } error[2];
688*4882a593Smuzhiyun } phases[] = {
689*4882a593Smuzhiyun { { BAD, GOOD } },
690*4882a593Smuzhiyun { { BAD, BAD } },
691*4882a593Smuzhiyun { { BAD, GOOD } },
692*4882a593Smuzhiyun { { GOOD, GOOD } }, /* sentinel */
693*4882a593Smuzhiyun };
694*4882a593Smuzhiyun struct intel_gt *gt = arg;
695*4882a593Smuzhiyun struct intel_engine_cs *engine;
696*4882a593Smuzhiyun enum intel_engine_id id;
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun /*
699*4882a593Smuzhiyun * We hook up the CS_MASTER_ERROR_INTERRUPT to have forewarning
700*4882a593Smuzhiyun * of invalid commands in user batches that will cause a GPU hang.
701*4882a593Smuzhiyun * This is a faster mechanism than using hangcheck/heartbeats, but
702*4882a593Smuzhiyun * only detects problems the HW knows about -- it will not warn when
703*4882a593Smuzhiyun * we kill the HW!
704*4882a593Smuzhiyun *
705*4882a593Smuzhiyun * To verify our detection and reset, we throw some invalid commands
706*4882a593Smuzhiyun * at the HW and wait for the interrupt.
707*4882a593Smuzhiyun */
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun if (!intel_has_reset_engine(gt))
710*4882a593Smuzhiyun return 0;
711*4882a593Smuzhiyun
712*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
713*4882a593Smuzhiyun const struct error_phase *p;
714*4882a593Smuzhiyun int err = 0;
715*4882a593Smuzhiyun
716*4882a593Smuzhiyun st_engine_heartbeat_disable(engine);
717*4882a593Smuzhiyun
718*4882a593Smuzhiyun for (p = phases; p->error[0] != GOOD; p++) {
719*4882a593Smuzhiyun struct i915_request *client[ARRAY_SIZE(phases->error)];
720*4882a593Smuzhiyun u32 *cs;
721*4882a593Smuzhiyun int i;
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun memset(client, 0, sizeof(*client));
724*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(client); i++) {
725*4882a593Smuzhiyun struct intel_context *ce;
726*4882a593Smuzhiyun struct i915_request *rq;
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun ce = intel_context_create(engine);
729*4882a593Smuzhiyun if (IS_ERR(ce)) {
730*4882a593Smuzhiyun err = PTR_ERR(ce);
731*4882a593Smuzhiyun goto out;
732*4882a593Smuzhiyun }
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun rq = intel_context_create_request(ce);
735*4882a593Smuzhiyun intel_context_put(ce);
736*4882a593Smuzhiyun if (IS_ERR(rq)) {
737*4882a593Smuzhiyun err = PTR_ERR(rq);
738*4882a593Smuzhiyun goto out;
739*4882a593Smuzhiyun }
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun if (rq->engine->emit_init_breadcrumb) {
742*4882a593Smuzhiyun err = rq->engine->emit_init_breadcrumb(rq);
743*4882a593Smuzhiyun if (err) {
744*4882a593Smuzhiyun i915_request_add(rq);
745*4882a593Smuzhiyun goto out;
746*4882a593Smuzhiyun }
747*4882a593Smuzhiyun }
748*4882a593Smuzhiyun
749*4882a593Smuzhiyun cs = intel_ring_begin(rq, 2);
750*4882a593Smuzhiyun if (IS_ERR(cs)) {
751*4882a593Smuzhiyun i915_request_add(rq);
752*4882a593Smuzhiyun err = PTR_ERR(cs);
753*4882a593Smuzhiyun goto out;
754*4882a593Smuzhiyun }
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun if (p->error[i]) {
757*4882a593Smuzhiyun *cs++ = 0xdeadbeef;
758*4882a593Smuzhiyun *cs++ = 0xdeadbeef;
759*4882a593Smuzhiyun } else {
760*4882a593Smuzhiyun *cs++ = MI_NOOP;
761*4882a593Smuzhiyun *cs++ = MI_NOOP;
762*4882a593Smuzhiyun }
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun client[i] = i915_request_get(rq);
765*4882a593Smuzhiyun i915_request_add(rq);
766*4882a593Smuzhiyun }
767*4882a593Smuzhiyun
768*4882a593Smuzhiyun err = wait_for_submit(engine, client[0], HZ / 2);
769*4882a593Smuzhiyun if (err) {
770*4882a593Smuzhiyun pr_err("%s: first request did not start within time!\n",
771*4882a593Smuzhiyun engine->name);
772*4882a593Smuzhiyun err = -ETIME;
773*4882a593Smuzhiyun goto out;
774*4882a593Smuzhiyun }
775*4882a593Smuzhiyun
776*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(client); i++) {
777*4882a593Smuzhiyun if (i915_request_wait(client[i], 0, HZ / 5) < 0)
778*4882a593Smuzhiyun pr_debug("%s: %s request incomplete!\n",
779*4882a593Smuzhiyun engine->name,
780*4882a593Smuzhiyun error_repr(p->error[i]));
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun if (!i915_request_started(client[i])) {
783*4882a593Smuzhiyun pr_err("%s: %s request not started!\n",
784*4882a593Smuzhiyun engine->name,
785*4882a593Smuzhiyun error_repr(p->error[i]));
786*4882a593Smuzhiyun err = -ETIME;
787*4882a593Smuzhiyun goto out;
788*4882a593Smuzhiyun }
789*4882a593Smuzhiyun
790*4882a593Smuzhiyun /* Kick the tasklet to process the error */
791*4882a593Smuzhiyun intel_engine_flush_submission(engine);
792*4882a593Smuzhiyun if (client[i]->fence.error != p->error[i]) {
793*4882a593Smuzhiyun pr_err("%s: %s request (%s) with wrong error code: %d\n",
794*4882a593Smuzhiyun engine->name,
795*4882a593Smuzhiyun error_repr(p->error[i]),
796*4882a593Smuzhiyun i915_request_completed(client[i]) ? "completed" : "running",
797*4882a593Smuzhiyun client[i]->fence.error);
798*4882a593Smuzhiyun err = -EINVAL;
799*4882a593Smuzhiyun goto out;
800*4882a593Smuzhiyun }
801*4882a593Smuzhiyun }
802*4882a593Smuzhiyun
803*4882a593Smuzhiyun out:
804*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(client); i++)
805*4882a593Smuzhiyun if (client[i])
806*4882a593Smuzhiyun i915_request_put(client[i]);
807*4882a593Smuzhiyun if (err) {
808*4882a593Smuzhiyun pr_err("%s: failed at phase[%zd] { %d, %d }\n",
809*4882a593Smuzhiyun engine->name, p - phases,
810*4882a593Smuzhiyun p->error[0], p->error[1]);
811*4882a593Smuzhiyun break;
812*4882a593Smuzhiyun }
813*4882a593Smuzhiyun }
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun st_engine_heartbeat_enable(engine);
816*4882a593Smuzhiyun if (err) {
817*4882a593Smuzhiyun intel_gt_set_wedged(gt);
818*4882a593Smuzhiyun return err;
819*4882a593Smuzhiyun }
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun
822*4882a593Smuzhiyun return 0;
823*4882a593Smuzhiyun }
824*4882a593Smuzhiyun
825*4882a593Smuzhiyun static int
emit_semaphore_chain(struct i915_request * rq,struct i915_vma * vma,int idx)826*4882a593Smuzhiyun emit_semaphore_chain(struct i915_request *rq, struct i915_vma *vma, int idx)
827*4882a593Smuzhiyun {
828*4882a593Smuzhiyun u32 *cs;
829*4882a593Smuzhiyun
830*4882a593Smuzhiyun cs = intel_ring_begin(rq, 10);
831*4882a593Smuzhiyun if (IS_ERR(cs))
832*4882a593Smuzhiyun return PTR_ERR(cs);
833*4882a593Smuzhiyun
834*4882a593Smuzhiyun *cs++ = MI_ARB_ON_OFF | MI_ARB_ENABLE;
835*4882a593Smuzhiyun
836*4882a593Smuzhiyun *cs++ = MI_SEMAPHORE_WAIT |
837*4882a593Smuzhiyun MI_SEMAPHORE_GLOBAL_GTT |
838*4882a593Smuzhiyun MI_SEMAPHORE_POLL |
839*4882a593Smuzhiyun MI_SEMAPHORE_SAD_NEQ_SDD;
840*4882a593Smuzhiyun *cs++ = 0;
841*4882a593Smuzhiyun *cs++ = i915_ggtt_offset(vma) + 4 * idx;
842*4882a593Smuzhiyun *cs++ = 0;
843*4882a593Smuzhiyun
844*4882a593Smuzhiyun if (idx > 0) {
845*4882a593Smuzhiyun *cs++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
846*4882a593Smuzhiyun *cs++ = i915_ggtt_offset(vma) + 4 * (idx - 1);
847*4882a593Smuzhiyun *cs++ = 0;
848*4882a593Smuzhiyun *cs++ = 1;
849*4882a593Smuzhiyun } else {
850*4882a593Smuzhiyun *cs++ = MI_NOOP;
851*4882a593Smuzhiyun *cs++ = MI_NOOP;
852*4882a593Smuzhiyun *cs++ = MI_NOOP;
853*4882a593Smuzhiyun *cs++ = MI_NOOP;
854*4882a593Smuzhiyun }
855*4882a593Smuzhiyun
856*4882a593Smuzhiyun *cs++ = MI_ARB_ON_OFF | MI_ARB_DISABLE;
857*4882a593Smuzhiyun
858*4882a593Smuzhiyun intel_ring_advance(rq, cs);
859*4882a593Smuzhiyun return 0;
860*4882a593Smuzhiyun }
861*4882a593Smuzhiyun
862*4882a593Smuzhiyun static struct i915_request *
semaphore_queue(struct intel_engine_cs * engine,struct i915_vma * vma,int idx)863*4882a593Smuzhiyun semaphore_queue(struct intel_engine_cs *engine, struct i915_vma *vma, int idx)
864*4882a593Smuzhiyun {
865*4882a593Smuzhiyun struct intel_context *ce;
866*4882a593Smuzhiyun struct i915_request *rq;
867*4882a593Smuzhiyun int err;
868*4882a593Smuzhiyun
869*4882a593Smuzhiyun ce = intel_context_create(engine);
870*4882a593Smuzhiyun if (IS_ERR(ce))
871*4882a593Smuzhiyun return ERR_CAST(ce);
872*4882a593Smuzhiyun
873*4882a593Smuzhiyun rq = intel_context_create_request(ce);
874*4882a593Smuzhiyun if (IS_ERR(rq))
875*4882a593Smuzhiyun goto out_ce;
876*4882a593Smuzhiyun
877*4882a593Smuzhiyun err = 0;
878*4882a593Smuzhiyun if (rq->engine->emit_init_breadcrumb)
879*4882a593Smuzhiyun err = rq->engine->emit_init_breadcrumb(rq);
880*4882a593Smuzhiyun if (err == 0)
881*4882a593Smuzhiyun err = emit_semaphore_chain(rq, vma, idx);
882*4882a593Smuzhiyun if (err == 0)
883*4882a593Smuzhiyun i915_request_get(rq);
884*4882a593Smuzhiyun i915_request_add(rq);
885*4882a593Smuzhiyun if (err)
886*4882a593Smuzhiyun rq = ERR_PTR(err);
887*4882a593Smuzhiyun
888*4882a593Smuzhiyun out_ce:
889*4882a593Smuzhiyun intel_context_put(ce);
890*4882a593Smuzhiyun return rq;
891*4882a593Smuzhiyun }
892*4882a593Smuzhiyun
893*4882a593Smuzhiyun static int
release_queue(struct intel_engine_cs * engine,struct i915_vma * vma,int idx,int prio)894*4882a593Smuzhiyun release_queue(struct intel_engine_cs *engine,
895*4882a593Smuzhiyun struct i915_vma *vma,
896*4882a593Smuzhiyun int idx, int prio)
897*4882a593Smuzhiyun {
898*4882a593Smuzhiyun struct i915_sched_attr attr = {
899*4882a593Smuzhiyun .priority = prio,
900*4882a593Smuzhiyun };
901*4882a593Smuzhiyun struct i915_request *rq;
902*4882a593Smuzhiyun u32 *cs;
903*4882a593Smuzhiyun
904*4882a593Smuzhiyun rq = intel_engine_create_kernel_request(engine);
905*4882a593Smuzhiyun if (IS_ERR(rq))
906*4882a593Smuzhiyun return PTR_ERR(rq);
907*4882a593Smuzhiyun
908*4882a593Smuzhiyun cs = intel_ring_begin(rq, 4);
909*4882a593Smuzhiyun if (IS_ERR(cs)) {
910*4882a593Smuzhiyun i915_request_add(rq);
911*4882a593Smuzhiyun return PTR_ERR(cs);
912*4882a593Smuzhiyun }
913*4882a593Smuzhiyun
914*4882a593Smuzhiyun *cs++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
915*4882a593Smuzhiyun *cs++ = i915_ggtt_offset(vma) + 4 * (idx - 1);
916*4882a593Smuzhiyun *cs++ = 0;
917*4882a593Smuzhiyun *cs++ = 1;
918*4882a593Smuzhiyun
919*4882a593Smuzhiyun intel_ring_advance(rq, cs);
920*4882a593Smuzhiyun
921*4882a593Smuzhiyun i915_request_get(rq);
922*4882a593Smuzhiyun i915_request_add(rq);
923*4882a593Smuzhiyun
924*4882a593Smuzhiyun local_bh_disable();
925*4882a593Smuzhiyun engine->schedule(rq, &attr);
926*4882a593Smuzhiyun local_bh_enable(); /* kick tasklet */
927*4882a593Smuzhiyun
928*4882a593Smuzhiyun i915_request_put(rq);
929*4882a593Smuzhiyun
930*4882a593Smuzhiyun return 0;
931*4882a593Smuzhiyun }
932*4882a593Smuzhiyun
933*4882a593Smuzhiyun static int
slice_semaphore_queue(struct intel_engine_cs * outer,struct i915_vma * vma,int count)934*4882a593Smuzhiyun slice_semaphore_queue(struct intel_engine_cs *outer,
935*4882a593Smuzhiyun struct i915_vma *vma,
936*4882a593Smuzhiyun int count)
937*4882a593Smuzhiyun {
938*4882a593Smuzhiyun struct intel_engine_cs *engine;
939*4882a593Smuzhiyun struct i915_request *head;
940*4882a593Smuzhiyun enum intel_engine_id id;
941*4882a593Smuzhiyun int err, i, n = 0;
942*4882a593Smuzhiyun
943*4882a593Smuzhiyun head = semaphore_queue(outer, vma, n++);
944*4882a593Smuzhiyun if (IS_ERR(head))
945*4882a593Smuzhiyun return PTR_ERR(head);
946*4882a593Smuzhiyun
947*4882a593Smuzhiyun for_each_engine(engine, outer->gt, id) {
948*4882a593Smuzhiyun for (i = 0; i < count; i++) {
949*4882a593Smuzhiyun struct i915_request *rq;
950*4882a593Smuzhiyun
951*4882a593Smuzhiyun rq = semaphore_queue(engine, vma, n++);
952*4882a593Smuzhiyun if (IS_ERR(rq)) {
953*4882a593Smuzhiyun err = PTR_ERR(rq);
954*4882a593Smuzhiyun goto out;
955*4882a593Smuzhiyun }
956*4882a593Smuzhiyun
957*4882a593Smuzhiyun i915_request_put(rq);
958*4882a593Smuzhiyun }
959*4882a593Smuzhiyun }
960*4882a593Smuzhiyun
961*4882a593Smuzhiyun err = release_queue(outer, vma, n, I915_PRIORITY_BARRIER);
962*4882a593Smuzhiyun if (err)
963*4882a593Smuzhiyun goto out;
964*4882a593Smuzhiyun
965*4882a593Smuzhiyun if (i915_request_wait(head, 0,
966*4882a593Smuzhiyun 2 * outer->gt->info.num_engines * (count + 2) * (count + 3)) < 0) {
967*4882a593Smuzhiyun pr_err("Failed to slice along semaphore chain of length (%d, %d)!\n",
968*4882a593Smuzhiyun count, n);
969*4882a593Smuzhiyun GEM_TRACE_DUMP();
970*4882a593Smuzhiyun intel_gt_set_wedged(outer->gt);
971*4882a593Smuzhiyun err = -EIO;
972*4882a593Smuzhiyun }
973*4882a593Smuzhiyun
974*4882a593Smuzhiyun out:
975*4882a593Smuzhiyun i915_request_put(head);
976*4882a593Smuzhiyun return err;
977*4882a593Smuzhiyun }
978*4882a593Smuzhiyun
live_timeslice_preempt(void * arg)979*4882a593Smuzhiyun static int live_timeslice_preempt(void *arg)
980*4882a593Smuzhiyun {
981*4882a593Smuzhiyun struct intel_gt *gt = arg;
982*4882a593Smuzhiyun struct drm_i915_gem_object *obj;
983*4882a593Smuzhiyun struct intel_engine_cs *engine;
984*4882a593Smuzhiyun enum intel_engine_id id;
985*4882a593Smuzhiyun struct i915_vma *vma;
986*4882a593Smuzhiyun void *vaddr;
987*4882a593Smuzhiyun int err = 0;
988*4882a593Smuzhiyun
989*4882a593Smuzhiyun /*
990*4882a593Smuzhiyun * If a request takes too long, we would like to give other users
991*4882a593Smuzhiyun * a fair go on the GPU. In particular, users may create batches
992*4882a593Smuzhiyun * that wait upon external input, where that input may even be
993*4882a593Smuzhiyun * supplied by another GPU job. To avoid blocking forever, we
994*4882a593Smuzhiyun * need to preempt the current task and replace it with another
995*4882a593Smuzhiyun * ready task.
996*4882a593Smuzhiyun */
997*4882a593Smuzhiyun if (!IS_ACTIVE(CONFIG_DRM_I915_TIMESLICE_DURATION))
998*4882a593Smuzhiyun return 0;
999*4882a593Smuzhiyun
1000*4882a593Smuzhiyun obj = i915_gem_object_create_internal(gt->i915, PAGE_SIZE);
1001*4882a593Smuzhiyun if (IS_ERR(obj))
1002*4882a593Smuzhiyun return PTR_ERR(obj);
1003*4882a593Smuzhiyun
1004*4882a593Smuzhiyun vma = i915_vma_instance(obj, >->ggtt->vm, NULL);
1005*4882a593Smuzhiyun if (IS_ERR(vma)) {
1006*4882a593Smuzhiyun err = PTR_ERR(vma);
1007*4882a593Smuzhiyun goto err_obj;
1008*4882a593Smuzhiyun }
1009*4882a593Smuzhiyun
1010*4882a593Smuzhiyun vaddr = i915_gem_object_pin_map(obj, I915_MAP_WC);
1011*4882a593Smuzhiyun if (IS_ERR(vaddr)) {
1012*4882a593Smuzhiyun err = PTR_ERR(vaddr);
1013*4882a593Smuzhiyun goto err_obj;
1014*4882a593Smuzhiyun }
1015*4882a593Smuzhiyun
1016*4882a593Smuzhiyun err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL);
1017*4882a593Smuzhiyun if (err)
1018*4882a593Smuzhiyun goto err_map;
1019*4882a593Smuzhiyun
1020*4882a593Smuzhiyun err = i915_vma_sync(vma);
1021*4882a593Smuzhiyun if (err)
1022*4882a593Smuzhiyun goto err_pin;
1023*4882a593Smuzhiyun
1024*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
1025*4882a593Smuzhiyun if (!intel_engine_has_preemption(engine))
1026*4882a593Smuzhiyun continue;
1027*4882a593Smuzhiyun
1028*4882a593Smuzhiyun memset(vaddr, 0, PAGE_SIZE);
1029*4882a593Smuzhiyun
1030*4882a593Smuzhiyun st_engine_heartbeat_disable(engine);
1031*4882a593Smuzhiyun err = slice_semaphore_queue(engine, vma, 5);
1032*4882a593Smuzhiyun st_engine_heartbeat_enable(engine);
1033*4882a593Smuzhiyun if (err)
1034*4882a593Smuzhiyun goto err_pin;
1035*4882a593Smuzhiyun
1036*4882a593Smuzhiyun if (igt_flush_test(gt->i915)) {
1037*4882a593Smuzhiyun err = -EIO;
1038*4882a593Smuzhiyun goto err_pin;
1039*4882a593Smuzhiyun }
1040*4882a593Smuzhiyun }
1041*4882a593Smuzhiyun
1042*4882a593Smuzhiyun err_pin:
1043*4882a593Smuzhiyun i915_vma_unpin(vma);
1044*4882a593Smuzhiyun err_map:
1045*4882a593Smuzhiyun i915_gem_object_unpin_map(obj);
1046*4882a593Smuzhiyun err_obj:
1047*4882a593Smuzhiyun i915_gem_object_put(obj);
1048*4882a593Smuzhiyun return err;
1049*4882a593Smuzhiyun }
1050*4882a593Smuzhiyun
1051*4882a593Smuzhiyun static struct i915_request *
create_rewinder(struct intel_context * ce,struct i915_request * wait,void * slot,int idx)1052*4882a593Smuzhiyun create_rewinder(struct intel_context *ce,
1053*4882a593Smuzhiyun struct i915_request *wait,
1054*4882a593Smuzhiyun void *slot, int idx)
1055*4882a593Smuzhiyun {
1056*4882a593Smuzhiyun const u32 offset =
1057*4882a593Smuzhiyun i915_ggtt_offset(ce->engine->status_page.vma) +
1058*4882a593Smuzhiyun offset_in_page(slot);
1059*4882a593Smuzhiyun struct i915_request *rq;
1060*4882a593Smuzhiyun u32 *cs;
1061*4882a593Smuzhiyun int err;
1062*4882a593Smuzhiyun
1063*4882a593Smuzhiyun rq = intel_context_create_request(ce);
1064*4882a593Smuzhiyun if (IS_ERR(rq))
1065*4882a593Smuzhiyun return rq;
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun if (wait) {
1068*4882a593Smuzhiyun err = i915_request_await_dma_fence(rq, &wait->fence);
1069*4882a593Smuzhiyun if (err)
1070*4882a593Smuzhiyun goto err;
1071*4882a593Smuzhiyun }
1072*4882a593Smuzhiyun
1073*4882a593Smuzhiyun cs = intel_ring_begin(rq, 14);
1074*4882a593Smuzhiyun if (IS_ERR(cs)) {
1075*4882a593Smuzhiyun err = PTR_ERR(cs);
1076*4882a593Smuzhiyun goto err;
1077*4882a593Smuzhiyun }
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun *cs++ = MI_ARB_ON_OFF | MI_ARB_ENABLE;
1080*4882a593Smuzhiyun *cs++ = MI_NOOP;
1081*4882a593Smuzhiyun
1082*4882a593Smuzhiyun *cs++ = MI_SEMAPHORE_WAIT |
1083*4882a593Smuzhiyun MI_SEMAPHORE_GLOBAL_GTT |
1084*4882a593Smuzhiyun MI_SEMAPHORE_POLL |
1085*4882a593Smuzhiyun MI_SEMAPHORE_SAD_GTE_SDD;
1086*4882a593Smuzhiyun *cs++ = idx;
1087*4882a593Smuzhiyun *cs++ = offset;
1088*4882a593Smuzhiyun *cs++ = 0;
1089*4882a593Smuzhiyun
1090*4882a593Smuzhiyun *cs++ = MI_STORE_REGISTER_MEM_GEN8 | MI_USE_GGTT;
1091*4882a593Smuzhiyun *cs++ = i915_mmio_reg_offset(RING_TIMESTAMP(rq->engine->mmio_base));
1092*4882a593Smuzhiyun *cs++ = offset + idx * sizeof(u32);
1093*4882a593Smuzhiyun *cs++ = 0;
1094*4882a593Smuzhiyun
1095*4882a593Smuzhiyun *cs++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
1096*4882a593Smuzhiyun *cs++ = offset;
1097*4882a593Smuzhiyun *cs++ = 0;
1098*4882a593Smuzhiyun *cs++ = idx + 1;
1099*4882a593Smuzhiyun
1100*4882a593Smuzhiyun intel_ring_advance(rq, cs);
1101*4882a593Smuzhiyun
1102*4882a593Smuzhiyun rq->sched.attr.priority = I915_PRIORITY_MASK;
1103*4882a593Smuzhiyun err = 0;
1104*4882a593Smuzhiyun err:
1105*4882a593Smuzhiyun i915_request_get(rq);
1106*4882a593Smuzhiyun i915_request_add(rq);
1107*4882a593Smuzhiyun if (err) {
1108*4882a593Smuzhiyun i915_request_put(rq);
1109*4882a593Smuzhiyun return ERR_PTR(err);
1110*4882a593Smuzhiyun }
1111*4882a593Smuzhiyun
1112*4882a593Smuzhiyun return rq;
1113*4882a593Smuzhiyun }
1114*4882a593Smuzhiyun
live_timeslice_rewind(void * arg)1115*4882a593Smuzhiyun static int live_timeslice_rewind(void *arg)
1116*4882a593Smuzhiyun {
1117*4882a593Smuzhiyun struct intel_gt *gt = arg;
1118*4882a593Smuzhiyun struct intel_engine_cs *engine;
1119*4882a593Smuzhiyun enum intel_engine_id id;
1120*4882a593Smuzhiyun
1121*4882a593Smuzhiyun /*
1122*4882a593Smuzhiyun * The usual presumption on timeslice expiration is that we replace
1123*4882a593Smuzhiyun * the active context with another. However, given a chain of
1124*4882a593Smuzhiyun * dependencies we may end up with replacing the context with itself,
1125*4882a593Smuzhiyun * but only a few of those requests, forcing us to rewind the
1126*4882a593Smuzhiyun * RING_TAIL of the original request.
1127*4882a593Smuzhiyun */
1128*4882a593Smuzhiyun if (!IS_ACTIVE(CONFIG_DRM_I915_TIMESLICE_DURATION))
1129*4882a593Smuzhiyun return 0;
1130*4882a593Smuzhiyun
1131*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
1132*4882a593Smuzhiyun enum { A1, A2, B1 };
1133*4882a593Smuzhiyun enum { X = 1, Z, Y };
1134*4882a593Smuzhiyun struct i915_request *rq[3] = {};
1135*4882a593Smuzhiyun struct intel_context *ce;
1136*4882a593Smuzhiyun unsigned long timeslice;
1137*4882a593Smuzhiyun int i, err = 0;
1138*4882a593Smuzhiyun u32 *slot;
1139*4882a593Smuzhiyun
1140*4882a593Smuzhiyun if (!intel_engine_has_timeslices(engine))
1141*4882a593Smuzhiyun continue;
1142*4882a593Smuzhiyun
1143*4882a593Smuzhiyun /*
1144*4882a593Smuzhiyun * A:rq1 -- semaphore wait, timestamp X
1145*4882a593Smuzhiyun * A:rq2 -- write timestamp Y
1146*4882a593Smuzhiyun *
1147*4882a593Smuzhiyun * B:rq1 [await A:rq1] -- write timestamp Z
1148*4882a593Smuzhiyun *
1149*4882a593Smuzhiyun * Force timeslice, release semaphore.
1150*4882a593Smuzhiyun *
1151*4882a593Smuzhiyun * Expect execution/evaluation order XZY
1152*4882a593Smuzhiyun */
1153*4882a593Smuzhiyun
1154*4882a593Smuzhiyun st_engine_heartbeat_disable(engine);
1155*4882a593Smuzhiyun timeslice = xchg(&engine->props.timeslice_duration_ms, 1);
1156*4882a593Smuzhiyun
1157*4882a593Smuzhiyun slot = memset32(engine->status_page.addr + 1000, 0, 4);
1158*4882a593Smuzhiyun
1159*4882a593Smuzhiyun ce = intel_context_create(engine);
1160*4882a593Smuzhiyun if (IS_ERR(ce)) {
1161*4882a593Smuzhiyun err = PTR_ERR(ce);
1162*4882a593Smuzhiyun goto err;
1163*4882a593Smuzhiyun }
1164*4882a593Smuzhiyun
1165*4882a593Smuzhiyun rq[A1] = create_rewinder(ce, NULL, slot, X);
1166*4882a593Smuzhiyun if (IS_ERR(rq[A1])) {
1167*4882a593Smuzhiyun intel_context_put(ce);
1168*4882a593Smuzhiyun goto err;
1169*4882a593Smuzhiyun }
1170*4882a593Smuzhiyun
1171*4882a593Smuzhiyun rq[A2] = create_rewinder(ce, NULL, slot, Y);
1172*4882a593Smuzhiyun intel_context_put(ce);
1173*4882a593Smuzhiyun if (IS_ERR(rq[A2]))
1174*4882a593Smuzhiyun goto err;
1175*4882a593Smuzhiyun
1176*4882a593Smuzhiyun err = wait_for_submit(engine, rq[A2], HZ / 2);
1177*4882a593Smuzhiyun if (err) {
1178*4882a593Smuzhiyun pr_err("%s: failed to submit first context\n",
1179*4882a593Smuzhiyun engine->name);
1180*4882a593Smuzhiyun goto err;
1181*4882a593Smuzhiyun }
1182*4882a593Smuzhiyun
1183*4882a593Smuzhiyun ce = intel_context_create(engine);
1184*4882a593Smuzhiyun if (IS_ERR(ce)) {
1185*4882a593Smuzhiyun err = PTR_ERR(ce);
1186*4882a593Smuzhiyun goto err;
1187*4882a593Smuzhiyun }
1188*4882a593Smuzhiyun
1189*4882a593Smuzhiyun rq[B1] = create_rewinder(ce, rq[A1], slot, Z);
1190*4882a593Smuzhiyun intel_context_put(ce);
1191*4882a593Smuzhiyun if (IS_ERR(rq[2]))
1192*4882a593Smuzhiyun goto err;
1193*4882a593Smuzhiyun
1194*4882a593Smuzhiyun err = wait_for_submit(engine, rq[B1], HZ / 2);
1195*4882a593Smuzhiyun if (err) {
1196*4882a593Smuzhiyun pr_err("%s: failed to submit second context\n",
1197*4882a593Smuzhiyun engine->name);
1198*4882a593Smuzhiyun goto err;
1199*4882a593Smuzhiyun }
1200*4882a593Smuzhiyun
1201*4882a593Smuzhiyun /* ELSP[] = { { A:rq1, A:rq2 }, { B:rq1 } } */
1202*4882a593Smuzhiyun ENGINE_TRACE(engine, "forcing tasklet for rewind\n");
1203*4882a593Smuzhiyun if (i915_request_is_active(rq[A2])) { /* semaphore yielded! */
1204*4882a593Smuzhiyun /* Wait for the timeslice to kick in */
1205*4882a593Smuzhiyun del_timer(&engine->execlists.timer);
1206*4882a593Smuzhiyun tasklet_hi_schedule(&engine->execlists.tasklet);
1207*4882a593Smuzhiyun intel_engine_flush_submission(engine);
1208*4882a593Smuzhiyun }
1209*4882a593Smuzhiyun /* -> ELSP[] = { { A:rq1 }, { B:rq1 } } */
1210*4882a593Smuzhiyun GEM_BUG_ON(!i915_request_is_active(rq[A1]));
1211*4882a593Smuzhiyun GEM_BUG_ON(!i915_request_is_active(rq[B1]));
1212*4882a593Smuzhiyun GEM_BUG_ON(i915_request_is_active(rq[A2]));
1213*4882a593Smuzhiyun
1214*4882a593Smuzhiyun /* Release the hounds! */
1215*4882a593Smuzhiyun slot[0] = 1;
1216*4882a593Smuzhiyun wmb(); /* "pairs" with GPU; paranoid kick of internal CPU$ */
1217*4882a593Smuzhiyun
1218*4882a593Smuzhiyun for (i = 1; i <= 3; i++) {
1219*4882a593Smuzhiyun unsigned long timeout = jiffies + HZ / 2;
1220*4882a593Smuzhiyun
1221*4882a593Smuzhiyun while (!READ_ONCE(slot[i]) &&
1222*4882a593Smuzhiyun time_before(jiffies, timeout))
1223*4882a593Smuzhiyun ;
1224*4882a593Smuzhiyun
1225*4882a593Smuzhiyun if (!time_before(jiffies, timeout)) {
1226*4882a593Smuzhiyun pr_err("%s: rq[%d] timed out\n",
1227*4882a593Smuzhiyun engine->name, i - 1);
1228*4882a593Smuzhiyun err = -ETIME;
1229*4882a593Smuzhiyun goto err;
1230*4882a593Smuzhiyun }
1231*4882a593Smuzhiyun
1232*4882a593Smuzhiyun pr_debug("%s: slot[%d]:%x\n", engine->name, i, slot[i]);
1233*4882a593Smuzhiyun }
1234*4882a593Smuzhiyun
1235*4882a593Smuzhiyun /* XZY: XZ < XY */
1236*4882a593Smuzhiyun if (slot[Z] - slot[X] >= slot[Y] - slot[X]) {
1237*4882a593Smuzhiyun pr_err("%s: timeslicing did not run context B [%u] before A [%u]!\n",
1238*4882a593Smuzhiyun engine->name,
1239*4882a593Smuzhiyun slot[Z] - slot[X],
1240*4882a593Smuzhiyun slot[Y] - slot[X]);
1241*4882a593Smuzhiyun err = -EINVAL;
1242*4882a593Smuzhiyun }
1243*4882a593Smuzhiyun
1244*4882a593Smuzhiyun err:
1245*4882a593Smuzhiyun memset32(&slot[0], -1, 4);
1246*4882a593Smuzhiyun wmb();
1247*4882a593Smuzhiyun
1248*4882a593Smuzhiyun engine->props.timeslice_duration_ms = timeslice;
1249*4882a593Smuzhiyun st_engine_heartbeat_enable(engine);
1250*4882a593Smuzhiyun for (i = 0; i < 3; i++)
1251*4882a593Smuzhiyun i915_request_put(rq[i]);
1252*4882a593Smuzhiyun if (igt_flush_test(gt->i915))
1253*4882a593Smuzhiyun err = -EIO;
1254*4882a593Smuzhiyun if (err)
1255*4882a593Smuzhiyun return err;
1256*4882a593Smuzhiyun }
1257*4882a593Smuzhiyun
1258*4882a593Smuzhiyun return 0;
1259*4882a593Smuzhiyun }
1260*4882a593Smuzhiyun
nop_request(struct intel_engine_cs * engine)1261*4882a593Smuzhiyun static struct i915_request *nop_request(struct intel_engine_cs *engine)
1262*4882a593Smuzhiyun {
1263*4882a593Smuzhiyun struct i915_request *rq;
1264*4882a593Smuzhiyun
1265*4882a593Smuzhiyun rq = intel_engine_create_kernel_request(engine);
1266*4882a593Smuzhiyun if (IS_ERR(rq))
1267*4882a593Smuzhiyun return rq;
1268*4882a593Smuzhiyun
1269*4882a593Smuzhiyun i915_request_get(rq);
1270*4882a593Smuzhiyun i915_request_add(rq);
1271*4882a593Smuzhiyun
1272*4882a593Smuzhiyun return rq;
1273*4882a593Smuzhiyun }
1274*4882a593Smuzhiyun
slice_timeout(struct intel_engine_cs * engine)1275*4882a593Smuzhiyun static long slice_timeout(struct intel_engine_cs *engine)
1276*4882a593Smuzhiyun {
1277*4882a593Smuzhiyun long timeout;
1278*4882a593Smuzhiyun
1279*4882a593Smuzhiyun /* Enough time for a timeslice to kick in, and kick out */
1280*4882a593Smuzhiyun timeout = 2 * msecs_to_jiffies_timeout(timeslice(engine));
1281*4882a593Smuzhiyun
1282*4882a593Smuzhiyun /* Enough time for the nop request to complete */
1283*4882a593Smuzhiyun timeout += HZ / 5;
1284*4882a593Smuzhiyun
1285*4882a593Smuzhiyun return timeout + 1;
1286*4882a593Smuzhiyun }
1287*4882a593Smuzhiyun
live_timeslice_queue(void * arg)1288*4882a593Smuzhiyun static int live_timeslice_queue(void *arg)
1289*4882a593Smuzhiyun {
1290*4882a593Smuzhiyun struct intel_gt *gt = arg;
1291*4882a593Smuzhiyun struct drm_i915_gem_object *obj;
1292*4882a593Smuzhiyun struct intel_engine_cs *engine;
1293*4882a593Smuzhiyun enum intel_engine_id id;
1294*4882a593Smuzhiyun struct i915_vma *vma;
1295*4882a593Smuzhiyun void *vaddr;
1296*4882a593Smuzhiyun int err = 0;
1297*4882a593Smuzhiyun
1298*4882a593Smuzhiyun /*
1299*4882a593Smuzhiyun * Make sure that even if ELSP[0] and ELSP[1] are filled with
1300*4882a593Smuzhiyun * timeslicing between them disabled, we *do* enable timeslicing
1301*4882a593Smuzhiyun * if the queue demands it. (Normally, we do not submit if
1302*4882a593Smuzhiyun * ELSP[1] is already occupied, so must rely on timeslicing to
1303*4882a593Smuzhiyun * eject ELSP[0] in favour of the queue.)
1304*4882a593Smuzhiyun */
1305*4882a593Smuzhiyun if (!IS_ACTIVE(CONFIG_DRM_I915_TIMESLICE_DURATION))
1306*4882a593Smuzhiyun return 0;
1307*4882a593Smuzhiyun
1308*4882a593Smuzhiyun obj = i915_gem_object_create_internal(gt->i915, PAGE_SIZE);
1309*4882a593Smuzhiyun if (IS_ERR(obj))
1310*4882a593Smuzhiyun return PTR_ERR(obj);
1311*4882a593Smuzhiyun
1312*4882a593Smuzhiyun vma = i915_vma_instance(obj, >->ggtt->vm, NULL);
1313*4882a593Smuzhiyun if (IS_ERR(vma)) {
1314*4882a593Smuzhiyun err = PTR_ERR(vma);
1315*4882a593Smuzhiyun goto err_obj;
1316*4882a593Smuzhiyun }
1317*4882a593Smuzhiyun
1318*4882a593Smuzhiyun vaddr = i915_gem_object_pin_map(obj, I915_MAP_WC);
1319*4882a593Smuzhiyun if (IS_ERR(vaddr)) {
1320*4882a593Smuzhiyun err = PTR_ERR(vaddr);
1321*4882a593Smuzhiyun goto err_obj;
1322*4882a593Smuzhiyun }
1323*4882a593Smuzhiyun
1324*4882a593Smuzhiyun err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL);
1325*4882a593Smuzhiyun if (err)
1326*4882a593Smuzhiyun goto err_map;
1327*4882a593Smuzhiyun
1328*4882a593Smuzhiyun err = i915_vma_sync(vma);
1329*4882a593Smuzhiyun if (err)
1330*4882a593Smuzhiyun goto err_pin;
1331*4882a593Smuzhiyun
1332*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
1333*4882a593Smuzhiyun struct i915_sched_attr attr = {
1334*4882a593Smuzhiyun .priority = I915_USER_PRIORITY(I915_PRIORITY_MAX),
1335*4882a593Smuzhiyun };
1336*4882a593Smuzhiyun struct i915_request *rq, *nop;
1337*4882a593Smuzhiyun
1338*4882a593Smuzhiyun if (!intel_engine_has_preemption(engine))
1339*4882a593Smuzhiyun continue;
1340*4882a593Smuzhiyun
1341*4882a593Smuzhiyun st_engine_heartbeat_disable(engine);
1342*4882a593Smuzhiyun memset(vaddr, 0, PAGE_SIZE);
1343*4882a593Smuzhiyun
1344*4882a593Smuzhiyun /* ELSP[0]: semaphore wait */
1345*4882a593Smuzhiyun rq = semaphore_queue(engine, vma, 0);
1346*4882a593Smuzhiyun if (IS_ERR(rq)) {
1347*4882a593Smuzhiyun err = PTR_ERR(rq);
1348*4882a593Smuzhiyun goto err_heartbeat;
1349*4882a593Smuzhiyun }
1350*4882a593Smuzhiyun engine->schedule(rq, &attr);
1351*4882a593Smuzhiyun err = wait_for_submit(engine, rq, HZ / 2);
1352*4882a593Smuzhiyun if (err) {
1353*4882a593Smuzhiyun pr_err("%s: Timed out trying to submit semaphores\n",
1354*4882a593Smuzhiyun engine->name);
1355*4882a593Smuzhiyun goto err_rq;
1356*4882a593Smuzhiyun }
1357*4882a593Smuzhiyun
1358*4882a593Smuzhiyun /* ELSP[1]: nop request */
1359*4882a593Smuzhiyun nop = nop_request(engine);
1360*4882a593Smuzhiyun if (IS_ERR(nop)) {
1361*4882a593Smuzhiyun err = PTR_ERR(nop);
1362*4882a593Smuzhiyun goto err_rq;
1363*4882a593Smuzhiyun }
1364*4882a593Smuzhiyun err = wait_for_submit(engine, nop, HZ / 2);
1365*4882a593Smuzhiyun i915_request_put(nop);
1366*4882a593Smuzhiyun if (err) {
1367*4882a593Smuzhiyun pr_err("%s: Timed out trying to submit nop\n",
1368*4882a593Smuzhiyun engine->name);
1369*4882a593Smuzhiyun goto err_rq;
1370*4882a593Smuzhiyun }
1371*4882a593Smuzhiyun
1372*4882a593Smuzhiyun GEM_BUG_ON(i915_request_completed(rq));
1373*4882a593Smuzhiyun GEM_BUG_ON(execlists_active(&engine->execlists) != rq);
1374*4882a593Smuzhiyun
1375*4882a593Smuzhiyun /* Queue: semaphore signal, matching priority as semaphore */
1376*4882a593Smuzhiyun err = release_queue(engine, vma, 1, effective_prio(rq));
1377*4882a593Smuzhiyun if (err)
1378*4882a593Smuzhiyun goto err_rq;
1379*4882a593Smuzhiyun
1380*4882a593Smuzhiyun /* Wait until we ack the release_queue and start timeslicing */
1381*4882a593Smuzhiyun do {
1382*4882a593Smuzhiyun cond_resched();
1383*4882a593Smuzhiyun intel_engine_flush_submission(engine);
1384*4882a593Smuzhiyun } while (READ_ONCE(engine->execlists.pending[0]));
1385*4882a593Smuzhiyun
1386*4882a593Smuzhiyun /* Timeslice every jiffy, so within 2 we should signal */
1387*4882a593Smuzhiyun if (i915_request_wait(rq, 0, slice_timeout(engine)) < 0) {
1388*4882a593Smuzhiyun struct drm_printer p =
1389*4882a593Smuzhiyun drm_info_printer(gt->i915->drm.dev);
1390*4882a593Smuzhiyun
1391*4882a593Smuzhiyun pr_err("%s: Failed to timeslice into queue\n",
1392*4882a593Smuzhiyun engine->name);
1393*4882a593Smuzhiyun intel_engine_dump(engine, &p,
1394*4882a593Smuzhiyun "%s\n", engine->name);
1395*4882a593Smuzhiyun
1396*4882a593Smuzhiyun memset(vaddr, 0xff, PAGE_SIZE);
1397*4882a593Smuzhiyun err = -EIO;
1398*4882a593Smuzhiyun }
1399*4882a593Smuzhiyun err_rq:
1400*4882a593Smuzhiyun i915_request_put(rq);
1401*4882a593Smuzhiyun err_heartbeat:
1402*4882a593Smuzhiyun st_engine_heartbeat_enable(engine);
1403*4882a593Smuzhiyun if (err)
1404*4882a593Smuzhiyun break;
1405*4882a593Smuzhiyun }
1406*4882a593Smuzhiyun
1407*4882a593Smuzhiyun err_pin:
1408*4882a593Smuzhiyun i915_vma_unpin(vma);
1409*4882a593Smuzhiyun err_map:
1410*4882a593Smuzhiyun i915_gem_object_unpin_map(obj);
1411*4882a593Smuzhiyun err_obj:
1412*4882a593Smuzhiyun i915_gem_object_put(obj);
1413*4882a593Smuzhiyun return err;
1414*4882a593Smuzhiyun }
1415*4882a593Smuzhiyun
live_timeslice_nopreempt(void * arg)1416*4882a593Smuzhiyun static int live_timeslice_nopreempt(void *arg)
1417*4882a593Smuzhiyun {
1418*4882a593Smuzhiyun struct intel_gt *gt = arg;
1419*4882a593Smuzhiyun struct intel_engine_cs *engine;
1420*4882a593Smuzhiyun enum intel_engine_id id;
1421*4882a593Smuzhiyun struct igt_spinner spin;
1422*4882a593Smuzhiyun int err = 0;
1423*4882a593Smuzhiyun
1424*4882a593Smuzhiyun /*
1425*4882a593Smuzhiyun * We should not timeslice into a request that is marked with
1426*4882a593Smuzhiyun * I915_REQUEST_NOPREEMPT.
1427*4882a593Smuzhiyun */
1428*4882a593Smuzhiyun if (!IS_ACTIVE(CONFIG_DRM_I915_TIMESLICE_DURATION))
1429*4882a593Smuzhiyun return 0;
1430*4882a593Smuzhiyun
1431*4882a593Smuzhiyun if (igt_spinner_init(&spin, gt))
1432*4882a593Smuzhiyun return -ENOMEM;
1433*4882a593Smuzhiyun
1434*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
1435*4882a593Smuzhiyun struct intel_context *ce;
1436*4882a593Smuzhiyun struct i915_request *rq;
1437*4882a593Smuzhiyun unsigned long timeslice;
1438*4882a593Smuzhiyun
1439*4882a593Smuzhiyun if (!intel_engine_has_preemption(engine))
1440*4882a593Smuzhiyun continue;
1441*4882a593Smuzhiyun
1442*4882a593Smuzhiyun ce = intel_context_create(engine);
1443*4882a593Smuzhiyun if (IS_ERR(ce)) {
1444*4882a593Smuzhiyun err = PTR_ERR(ce);
1445*4882a593Smuzhiyun break;
1446*4882a593Smuzhiyun }
1447*4882a593Smuzhiyun
1448*4882a593Smuzhiyun st_engine_heartbeat_disable(engine);
1449*4882a593Smuzhiyun timeslice = xchg(&engine->props.timeslice_duration_ms, 1);
1450*4882a593Smuzhiyun
1451*4882a593Smuzhiyun /* Create an unpreemptible spinner */
1452*4882a593Smuzhiyun
1453*4882a593Smuzhiyun rq = igt_spinner_create_request(&spin, ce, MI_ARB_CHECK);
1454*4882a593Smuzhiyun intel_context_put(ce);
1455*4882a593Smuzhiyun if (IS_ERR(rq)) {
1456*4882a593Smuzhiyun err = PTR_ERR(rq);
1457*4882a593Smuzhiyun goto out_heartbeat;
1458*4882a593Smuzhiyun }
1459*4882a593Smuzhiyun
1460*4882a593Smuzhiyun i915_request_get(rq);
1461*4882a593Smuzhiyun i915_request_add(rq);
1462*4882a593Smuzhiyun
1463*4882a593Smuzhiyun if (!igt_wait_for_spinner(&spin, rq)) {
1464*4882a593Smuzhiyun i915_request_put(rq);
1465*4882a593Smuzhiyun err = -ETIME;
1466*4882a593Smuzhiyun goto out_spin;
1467*4882a593Smuzhiyun }
1468*4882a593Smuzhiyun
1469*4882a593Smuzhiyun set_bit(I915_FENCE_FLAG_NOPREEMPT, &rq->fence.flags);
1470*4882a593Smuzhiyun i915_request_put(rq);
1471*4882a593Smuzhiyun
1472*4882a593Smuzhiyun /* Followed by a maximum priority barrier (heartbeat) */
1473*4882a593Smuzhiyun
1474*4882a593Smuzhiyun ce = intel_context_create(engine);
1475*4882a593Smuzhiyun if (IS_ERR(ce)) {
1476*4882a593Smuzhiyun err = PTR_ERR(ce);
1477*4882a593Smuzhiyun goto out_spin;
1478*4882a593Smuzhiyun }
1479*4882a593Smuzhiyun
1480*4882a593Smuzhiyun rq = intel_context_create_request(ce);
1481*4882a593Smuzhiyun intel_context_put(ce);
1482*4882a593Smuzhiyun if (IS_ERR(rq)) {
1483*4882a593Smuzhiyun err = PTR_ERR(rq);
1484*4882a593Smuzhiyun goto out_spin;
1485*4882a593Smuzhiyun }
1486*4882a593Smuzhiyun
1487*4882a593Smuzhiyun rq->sched.attr.priority = I915_PRIORITY_BARRIER;
1488*4882a593Smuzhiyun i915_request_get(rq);
1489*4882a593Smuzhiyun i915_request_add(rq);
1490*4882a593Smuzhiyun
1491*4882a593Smuzhiyun /*
1492*4882a593Smuzhiyun * Wait until the barrier is in ELSP, and we know timeslicing
1493*4882a593Smuzhiyun * will have been activated.
1494*4882a593Smuzhiyun */
1495*4882a593Smuzhiyun if (wait_for_submit(engine, rq, HZ / 2)) {
1496*4882a593Smuzhiyun i915_request_put(rq);
1497*4882a593Smuzhiyun err = -ETIME;
1498*4882a593Smuzhiyun goto out_spin;
1499*4882a593Smuzhiyun }
1500*4882a593Smuzhiyun
1501*4882a593Smuzhiyun /*
1502*4882a593Smuzhiyun * Since the ELSP[0] request is unpreemptible, it should not
1503*4882a593Smuzhiyun * allow the maximum priority barrier through. Wait long
1504*4882a593Smuzhiyun * enough to see if it is timesliced in by mistake.
1505*4882a593Smuzhiyun */
1506*4882a593Smuzhiyun if (i915_request_wait(rq, 0, slice_timeout(engine)) >= 0) {
1507*4882a593Smuzhiyun pr_err("%s: I915_PRIORITY_BARRIER request completed, bypassing no-preempt request\n",
1508*4882a593Smuzhiyun engine->name);
1509*4882a593Smuzhiyun err = -EINVAL;
1510*4882a593Smuzhiyun }
1511*4882a593Smuzhiyun i915_request_put(rq);
1512*4882a593Smuzhiyun
1513*4882a593Smuzhiyun out_spin:
1514*4882a593Smuzhiyun igt_spinner_end(&spin);
1515*4882a593Smuzhiyun out_heartbeat:
1516*4882a593Smuzhiyun xchg(&engine->props.timeslice_duration_ms, timeslice);
1517*4882a593Smuzhiyun st_engine_heartbeat_enable(engine);
1518*4882a593Smuzhiyun if (err)
1519*4882a593Smuzhiyun break;
1520*4882a593Smuzhiyun
1521*4882a593Smuzhiyun if (igt_flush_test(gt->i915)) {
1522*4882a593Smuzhiyun err = -EIO;
1523*4882a593Smuzhiyun break;
1524*4882a593Smuzhiyun }
1525*4882a593Smuzhiyun }
1526*4882a593Smuzhiyun
1527*4882a593Smuzhiyun igt_spinner_fini(&spin);
1528*4882a593Smuzhiyun return err;
1529*4882a593Smuzhiyun }
1530*4882a593Smuzhiyun
live_busywait_preempt(void * arg)1531*4882a593Smuzhiyun static int live_busywait_preempt(void *arg)
1532*4882a593Smuzhiyun {
1533*4882a593Smuzhiyun struct intel_gt *gt = arg;
1534*4882a593Smuzhiyun struct i915_gem_context *ctx_hi, *ctx_lo;
1535*4882a593Smuzhiyun struct intel_engine_cs *engine;
1536*4882a593Smuzhiyun struct drm_i915_gem_object *obj;
1537*4882a593Smuzhiyun struct i915_vma *vma;
1538*4882a593Smuzhiyun enum intel_engine_id id;
1539*4882a593Smuzhiyun int err = -ENOMEM;
1540*4882a593Smuzhiyun u32 *map;
1541*4882a593Smuzhiyun
1542*4882a593Smuzhiyun /*
1543*4882a593Smuzhiyun * Verify that even without HAS_LOGICAL_RING_PREEMPTION, we can
1544*4882a593Smuzhiyun * preempt the busywaits used to synchronise between rings.
1545*4882a593Smuzhiyun */
1546*4882a593Smuzhiyun
1547*4882a593Smuzhiyun ctx_hi = kernel_context(gt->i915);
1548*4882a593Smuzhiyun if (!ctx_hi)
1549*4882a593Smuzhiyun return -ENOMEM;
1550*4882a593Smuzhiyun ctx_hi->sched.priority =
1551*4882a593Smuzhiyun I915_USER_PRIORITY(I915_CONTEXT_MAX_USER_PRIORITY);
1552*4882a593Smuzhiyun
1553*4882a593Smuzhiyun ctx_lo = kernel_context(gt->i915);
1554*4882a593Smuzhiyun if (!ctx_lo)
1555*4882a593Smuzhiyun goto err_ctx_hi;
1556*4882a593Smuzhiyun ctx_lo->sched.priority =
1557*4882a593Smuzhiyun I915_USER_PRIORITY(I915_CONTEXT_MIN_USER_PRIORITY);
1558*4882a593Smuzhiyun
1559*4882a593Smuzhiyun obj = i915_gem_object_create_internal(gt->i915, PAGE_SIZE);
1560*4882a593Smuzhiyun if (IS_ERR(obj)) {
1561*4882a593Smuzhiyun err = PTR_ERR(obj);
1562*4882a593Smuzhiyun goto err_ctx_lo;
1563*4882a593Smuzhiyun }
1564*4882a593Smuzhiyun
1565*4882a593Smuzhiyun map = i915_gem_object_pin_map(obj, I915_MAP_WC);
1566*4882a593Smuzhiyun if (IS_ERR(map)) {
1567*4882a593Smuzhiyun err = PTR_ERR(map);
1568*4882a593Smuzhiyun goto err_obj;
1569*4882a593Smuzhiyun }
1570*4882a593Smuzhiyun
1571*4882a593Smuzhiyun vma = i915_vma_instance(obj, >->ggtt->vm, NULL);
1572*4882a593Smuzhiyun if (IS_ERR(vma)) {
1573*4882a593Smuzhiyun err = PTR_ERR(vma);
1574*4882a593Smuzhiyun goto err_map;
1575*4882a593Smuzhiyun }
1576*4882a593Smuzhiyun
1577*4882a593Smuzhiyun err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL);
1578*4882a593Smuzhiyun if (err)
1579*4882a593Smuzhiyun goto err_map;
1580*4882a593Smuzhiyun
1581*4882a593Smuzhiyun err = i915_vma_sync(vma);
1582*4882a593Smuzhiyun if (err)
1583*4882a593Smuzhiyun goto err_vma;
1584*4882a593Smuzhiyun
1585*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
1586*4882a593Smuzhiyun struct i915_request *lo, *hi;
1587*4882a593Smuzhiyun struct igt_live_test t;
1588*4882a593Smuzhiyun u32 *cs;
1589*4882a593Smuzhiyun
1590*4882a593Smuzhiyun if (!intel_engine_has_preemption(engine))
1591*4882a593Smuzhiyun continue;
1592*4882a593Smuzhiyun
1593*4882a593Smuzhiyun if (!intel_engine_can_store_dword(engine))
1594*4882a593Smuzhiyun continue;
1595*4882a593Smuzhiyun
1596*4882a593Smuzhiyun if (igt_live_test_begin(&t, gt->i915, __func__, engine->name)) {
1597*4882a593Smuzhiyun err = -EIO;
1598*4882a593Smuzhiyun goto err_vma;
1599*4882a593Smuzhiyun }
1600*4882a593Smuzhiyun
1601*4882a593Smuzhiyun /*
1602*4882a593Smuzhiyun * We create two requests. The low priority request
1603*4882a593Smuzhiyun * busywaits on a semaphore (inside the ringbuffer where
1604*4882a593Smuzhiyun * is should be preemptible) and the high priority requests
1605*4882a593Smuzhiyun * uses a MI_STORE_DWORD_IMM to update the semaphore value
1606*4882a593Smuzhiyun * allowing the first request to complete. If preemption
1607*4882a593Smuzhiyun * fails, we hang instead.
1608*4882a593Smuzhiyun */
1609*4882a593Smuzhiyun
1610*4882a593Smuzhiyun lo = igt_request_alloc(ctx_lo, engine);
1611*4882a593Smuzhiyun if (IS_ERR(lo)) {
1612*4882a593Smuzhiyun err = PTR_ERR(lo);
1613*4882a593Smuzhiyun goto err_vma;
1614*4882a593Smuzhiyun }
1615*4882a593Smuzhiyun
1616*4882a593Smuzhiyun cs = intel_ring_begin(lo, 8);
1617*4882a593Smuzhiyun if (IS_ERR(cs)) {
1618*4882a593Smuzhiyun err = PTR_ERR(cs);
1619*4882a593Smuzhiyun i915_request_add(lo);
1620*4882a593Smuzhiyun goto err_vma;
1621*4882a593Smuzhiyun }
1622*4882a593Smuzhiyun
1623*4882a593Smuzhiyun *cs++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
1624*4882a593Smuzhiyun *cs++ = i915_ggtt_offset(vma);
1625*4882a593Smuzhiyun *cs++ = 0;
1626*4882a593Smuzhiyun *cs++ = 1;
1627*4882a593Smuzhiyun
1628*4882a593Smuzhiyun /* XXX Do we need a flush + invalidate here? */
1629*4882a593Smuzhiyun
1630*4882a593Smuzhiyun *cs++ = MI_SEMAPHORE_WAIT |
1631*4882a593Smuzhiyun MI_SEMAPHORE_GLOBAL_GTT |
1632*4882a593Smuzhiyun MI_SEMAPHORE_POLL |
1633*4882a593Smuzhiyun MI_SEMAPHORE_SAD_EQ_SDD;
1634*4882a593Smuzhiyun *cs++ = 0;
1635*4882a593Smuzhiyun *cs++ = i915_ggtt_offset(vma);
1636*4882a593Smuzhiyun *cs++ = 0;
1637*4882a593Smuzhiyun
1638*4882a593Smuzhiyun intel_ring_advance(lo, cs);
1639*4882a593Smuzhiyun
1640*4882a593Smuzhiyun i915_request_get(lo);
1641*4882a593Smuzhiyun i915_request_add(lo);
1642*4882a593Smuzhiyun
1643*4882a593Smuzhiyun if (wait_for(READ_ONCE(*map), 10)) {
1644*4882a593Smuzhiyun i915_request_put(lo);
1645*4882a593Smuzhiyun err = -ETIMEDOUT;
1646*4882a593Smuzhiyun goto err_vma;
1647*4882a593Smuzhiyun }
1648*4882a593Smuzhiyun
1649*4882a593Smuzhiyun /* Low priority request should be busywaiting now */
1650*4882a593Smuzhiyun if (i915_request_wait(lo, 0, 1) != -ETIME) {
1651*4882a593Smuzhiyun i915_request_put(lo);
1652*4882a593Smuzhiyun pr_err("%s: Busywaiting request did not!\n",
1653*4882a593Smuzhiyun engine->name);
1654*4882a593Smuzhiyun err = -EIO;
1655*4882a593Smuzhiyun goto err_vma;
1656*4882a593Smuzhiyun }
1657*4882a593Smuzhiyun
1658*4882a593Smuzhiyun hi = igt_request_alloc(ctx_hi, engine);
1659*4882a593Smuzhiyun if (IS_ERR(hi)) {
1660*4882a593Smuzhiyun err = PTR_ERR(hi);
1661*4882a593Smuzhiyun i915_request_put(lo);
1662*4882a593Smuzhiyun goto err_vma;
1663*4882a593Smuzhiyun }
1664*4882a593Smuzhiyun
1665*4882a593Smuzhiyun cs = intel_ring_begin(hi, 4);
1666*4882a593Smuzhiyun if (IS_ERR(cs)) {
1667*4882a593Smuzhiyun err = PTR_ERR(cs);
1668*4882a593Smuzhiyun i915_request_add(hi);
1669*4882a593Smuzhiyun i915_request_put(lo);
1670*4882a593Smuzhiyun goto err_vma;
1671*4882a593Smuzhiyun }
1672*4882a593Smuzhiyun
1673*4882a593Smuzhiyun *cs++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
1674*4882a593Smuzhiyun *cs++ = i915_ggtt_offset(vma);
1675*4882a593Smuzhiyun *cs++ = 0;
1676*4882a593Smuzhiyun *cs++ = 0;
1677*4882a593Smuzhiyun
1678*4882a593Smuzhiyun intel_ring_advance(hi, cs);
1679*4882a593Smuzhiyun i915_request_add(hi);
1680*4882a593Smuzhiyun
1681*4882a593Smuzhiyun if (i915_request_wait(lo, 0, HZ / 5) < 0) {
1682*4882a593Smuzhiyun struct drm_printer p = drm_info_printer(gt->i915->drm.dev);
1683*4882a593Smuzhiyun
1684*4882a593Smuzhiyun pr_err("%s: Failed to preempt semaphore busywait!\n",
1685*4882a593Smuzhiyun engine->name);
1686*4882a593Smuzhiyun
1687*4882a593Smuzhiyun intel_engine_dump(engine, &p, "%s\n", engine->name);
1688*4882a593Smuzhiyun GEM_TRACE_DUMP();
1689*4882a593Smuzhiyun
1690*4882a593Smuzhiyun i915_request_put(lo);
1691*4882a593Smuzhiyun intel_gt_set_wedged(gt);
1692*4882a593Smuzhiyun err = -EIO;
1693*4882a593Smuzhiyun goto err_vma;
1694*4882a593Smuzhiyun }
1695*4882a593Smuzhiyun GEM_BUG_ON(READ_ONCE(*map));
1696*4882a593Smuzhiyun i915_request_put(lo);
1697*4882a593Smuzhiyun
1698*4882a593Smuzhiyun if (igt_live_test_end(&t)) {
1699*4882a593Smuzhiyun err = -EIO;
1700*4882a593Smuzhiyun goto err_vma;
1701*4882a593Smuzhiyun }
1702*4882a593Smuzhiyun }
1703*4882a593Smuzhiyun
1704*4882a593Smuzhiyun err = 0;
1705*4882a593Smuzhiyun err_vma:
1706*4882a593Smuzhiyun i915_vma_unpin(vma);
1707*4882a593Smuzhiyun err_map:
1708*4882a593Smuzhiyun i915_gem_object_unpin_map(obj);
1709*4882a593Smuzhiyun err_obj:
1710*4882a593Smuzhiyun i915_gem_object_put(obj);
1711*4882a593Smuzhiyun err_ctx_lo:
1712*4882a593Smuzhiyun kernel_context_close(ctx_lo);
1713*4882a593Smuzhiyun err_ctx_hi:
1714*4882a593Smuzhiyun kernel_context_close(ctx_hi);
1715*4882a593Smuzhiyun return err;
1716*4882a593Smuzhiyun }
1717*4882a593Smuzhiyun
1718*4882a593Smuzhiyun static struct i915_request *
spinner_create_request(struct igt_spinner * spin,struct i915_gem_context * ctx,struct intel_engine_cs * engine,u32 arb)1719*4882a593Smuzhiyun spinner_create_request(struct igt_spinner *spin,
1720*4882a593Smuzhiyun struct i915_gem_context *ctx,
1721*4882a593Smuzhiyun struct intel_engine_cs *engine,
1722*4882a593Smuzhiyun u32 arb)
1723*4882a593Smuzhiyun {
1724*4882a593Smuzhiyun struct intel_context *ce;
1725*4882a593Smuzhiyun struct i915_request *rq;
1726*4882a593Smuzhiyun
1727*4882a593Smuzhiyun ce = i915_gem_context_get_engine(ctx, engine->legacy_idx);
1728*4882a593Smuzhiyun if (IS_ERR(ce))
1729*4882a593Smuzhiyun return ERR_CAST(ce);
1730*4882a593Smuzhiyun
1731*4882a593Smuzhiyun rq = igt_spinner_create_request(spin, ce, arb);
1732*4882a593Smuzhiyun intel_context_put(ce);
1733*4882a593Smuzhiyun return rq;
1734*4882a593Smuzhiyun }
1735*4882a593Smuzhiyun
live_preempt(void * arg)1736*4882a593Smuzhiyun static int live_preempt(void *arg)
1737*4882a593Smuzhiyun {
1738*4882a593Smuzhiyun struct intel_gt *gt = arg;
1739*4882a593Smuzhiyun struct i915_gem_context *ctx_hi, *ctx_lo;
1740*4882a593Smuzhiyun struct igt_spinner spin_hi, spin_lo;
1741*4882a593Smuzhiyun struct intel_engine_cs *engine;
1742*4882a593Smuzhiyun enum intel_engine_id id;
1743*4882a593Smuzhiyun int err = -ENOMEM;
1744*4882a593Smuzhiyun
1745*4882a593Smuzhiyun if (!HAS_LOGICAL_RING_PREEMPTION(gt->i915))
1746*4882a593Smuzhiyun return 0;
1747*4882a593Smuzhiyun
1748*4882a593Smuzhiyun if (!(gt->i915->caps.scheduler & I915_SCHEDULER_CAP_PREEMPTION))
1749*4882a593Smuzhiyun pr_err("Logical preemption supported, but not exposed\n");
1750*4882a593Smuzhiyun
1751*4882a593Smuzhiyun if (igt_spinner_init(&spin_hi, gt))
1752*4882a593Smuzhiyun return -ENOMEM;
1753*4882a593Smuzhiyun
1754*4882a593Smuzhiyun if (igt_spinner_init(&spin_lo, gt))
1755*4882a593Smuzhiyun goto err_spin_hi;
1756*4882a593Smuzhiyun
1757*4882a593Smuzhiyun ctx_hi = kernel_context(gt->i915);
1758*4882a593Smuzhiyun if (!ctx_hi)
1759*4882a593Smuzhiyun goto err_spin_lo;
1760*4882a593Smuzhiyun ctx_hi->sched.priority =
1761*4882a593Smuzhiyun I915_USER_PRIORITY(I915_CONTEXT_MAX_USER_PRIORITY);
1762*4882a593Smuzhiyun
1763*4882a593Smuzhiyun ctx_lo = kernel_context(gt->i915);
1764*4882a593Smuzhiyun if (!ctx_lo)
1765*4882a593Smuzhiyun goto err_ctx_hi;
1766*4882a593Smuzhiyun ctx_lo->sched.priority =
1767*4882a593Smuzhiyun I915_USER_PRIORITY(I915_CONTEXT_MIN_USER_PRIORITY);
1768*4882a593Smuzhiyun
1769*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
1770*4882a593Smuzhiyun struct igt_live_test t;
1771*4882a593Smuzhiyun struct i915_request *rq;
1772*4882a593Smuzhiyun
1773*4882a593Smuzhiyun if (!intel_engine_has_preemption(engine))
1774*4882a593Smuzhiyun continue;
1775*4882a593Smuzhiyun
1776*4882a593Smuzhiyun if (igt_live_test_begin(&t, gt->i915, __func__, engine->name)) {
1777*4882a593Smuzhiyun err = -EIO;
1778*4882a593Smuzhiyun goto err_ctx_lo;
1779*4882a593Smuzhiyun }
1780*4882a593Smuzhiyun
1781*4882a593Smuzhiyun rq = spinner_create_request(&spin_lo, ctx_lo, engine,
1782*4882a593Smuzhiyun MI_ARB_CHECK);
1783*4882a593Smuzhiyun if (IS_ERR(rq)) {
1784*4882a593Smuzhiyun err = PTR_ERR(rq);
1785*4882a593Smuzhiyun goto err_ctx_lo;
1786*4882a593Smuzhiyun }
1787*4882a593Smuzhiyun
1788*4882a593Smuzhiyun i915_request_add(rq);
1789*4882a593Smuzhiyun if (!igt_wait_for_spinner(&spin_lo, rq)) {
1790*4882a593Smuzhiyun GEM_TRACE("lo spinner failed to start\n");
1791*4882a593Smuzhiyun GEM_TRACE_DUMP();
1792*4882a593Smuzhiyun intel_gt_set_wedged(gt);
1793*4882a593Smuzhiyun err = -EIO;
1794*4882a593Smuzhiyun goto err_ctx_lo;
1795*4882a593Smuzhiyun }
1796*4882a593Smuzhiyun
1797*4882a593Smuzhiyun rq = spinner_create_request(&spin_hi, ctx_hi, engine,
1798*4882a593Smuzhiyun MI_ARB_CHECK);
1799*4882a593Smuzhiyun if (IS_ERR(rq)) {
1800*4882a593Smuzhiyun igt_spinner_end(&spin_lo);
1801*4882a593Smuzhiyun err = PTR_ERR(rq);
1802*4882a593Smuzhiyun goto err_ctx_lo;
1803*4882a593Smuzhiyun }
1804*4882a593Smuzhiyun
1805*4882a593Smuzhiyun i915_request_add(rq);
1806*4882a593Smuzhiyun if (!igt_wait_for_spinner(&spin_hi, rq)) {
1807*4882a593Smuzhiyun GEM_TRACE("hi spinner failed to start\n");
1808*4882a593Smuzhiyun GEM_TRACE_DUMP();
1809*4882a593Smuzhiyun intel_gt_set_wedged(gt);
1810*4882a593Smuzhiyun err = -EIO;
1811*4882a593Smuzhiyun goto err_ctx_lo;
1812*4882a593Smuzhiyun }
1813*4882a593Smuzhiyun
1814*4882a593Smuzhiyun igt_spinner_end(&spin_hi);
1815*4882a593Smuzhiyun igt_spinner_end(&spin_lo);
1816*4882a593Smuzhiyun
1817*4882a593Smuzhiyun if (igt_live_test_end(&t)) {
1818*4882a593Smuzhiyun err = -EIO;
1819*4882a593Smuzhiyun goto err_ctx_lo;
1820*4882a593Smuzhiyun }
1821*4882a593Smuzhiyun }
1822*4882a593Smuzhiyun
1823*4882a593Smuzhiyun err = 0;
1824*4882a593Smuzhiyun err_ctx_lo:
1825*4882a593Smuzhiyun kernel_context_close(ctx_lo);
1826*4882a593Smuzhiyun err_ctx_hi:
1827*4882a593Smuzhiyun kernel_context_close(ctx_hi);
1828*4882a593Smuzhiyun err_spin_lo:
1829*4882a593Smuzhiyun igt_spinner_fini(&spin_lo);
1830*4882a593Smuzhiyun err_spin_hi:
1831*4882a593Smuzhiyun igt_spinner_fini(&spin_hi);
1832*4882a593Smuzhiyun return err;
1833*4882a593Smuzhiyun }
1834*4882a593Smuzhiyun
live_late_preempt(void * arg)1835*4882a593Smuzhiyun static int live_late_preempt(void *arg)
1836*4882a593Smuzhiyun {
1837*4882a593Smuzhiyun struct intel_gt *gt = arg;
1838*4882a593Smuzhiyun struct i915_gem_context *ctx_hi, *ctx_lo;
1839*4882a593Smuzhiyun struct igt_spinner spin_hi, spin_lo;
1840*4882a593Smuzhiyun struct intel_engine_cs *engine;
1841*4882a593Smuzhiyun struct i915_sched_attr attr = {};
1842*4882a593Smuzhiyun enum intel_engine_id id;
1843*4882a593Smuzhiyun int err = -ENOMEM;
1844*4882a593Smuzhiyun
1845*4882a593Smuzhiyun if (!HAS_LOGICAL_RING_PREEMPTION(gt->i915))
1846*4882a593Smuzhiyun return 0;
1847*4882a593Smuzhiyun
1848*4882a593Smuzhiyun if (igt_spinner_init(&spin_hi, gt))
1849*4882a593Smuzhiyun return -ENOMEM;
1850*4882a593Smuzhiyun
1851*4882a593Smuzhiyun if (igt_spinner_init(&spin_lo, gt))
1852*4882a593Smuzhiyun goto err_spin_hi;
1853*4882a593Smuzhiyun
1854*4882a593Smuzhiyun ctx_hi = kernel_context(gt->i915);
1855*4882a593Smuzhiyun if (!ctx_hi)
1856*4882a593Smuzhiyun goto err_spin_lo;
1857*4882a593Smuzhiyun
1858*4882a593Smuzhiyun ctx_lo = kernel_context(gt->i915);
1859*4882a593Smuzhiyun if (!ctx_lo)
1860*4882a593Smuzhiyun goto err_ctx_hi;
1861*4882a593Smuzhiyun
1862*4882a593Smuzhiyun /* Make sure ctx_lo stays before ctx_hi until we trigger preemption. */
1863*4882a593Smuzhiyun ctx_lo->sched.priority = I915_USER_PRIORITY(1);
1864*4882a593Smuzhiyun
1865*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
1866*4882a593Smuzhiyun struct igt_live_test t;
1867*4882a593Smuzhiyun struct i915_request *rq;
1868*4882a593Smuzhiyun
1869*4882a593Smuzhiyun if (!intel_engine_has_preemption(engine))
1870*4882a593Smuzhiyun continue;
1871*4882a593Smuzhiyun
1872*4882a593Smuzhiyun if (igt_live_test_begin(&t, gt->i915, __func__, engine->name)) {
1873*4882a593Smuzhiyun err = -EIO;
1874*4882a593Smuzhiyun goto err_ctx_lo;
1875*4882a593Smuzhiyun }
1876*4882a593Smuzhiyun
1877*4882a593Smuzhiyun rq = spinner_create_request(&spin_lo, ctx_lo, engine,
1878*4882a593Smuzhiyun MI_ARB_CHECK);
1879*4882a593Smuzhiyun if (IS_ERR(rq)) {
1880*4882a593Smuzhiyun err = PTR_ERR(rq);
1881*4882a593Smuzhiyun goto err_ctx_lo;
1882*4882a593Smuzhiyun }
1883*4882a593Smuzhiyun
1884*4882a593Smuzhiyun i915_request_add(rq);
1885*4882a593Smuzhiyun if (!igt_wait_for_spinner(&spin_lo, rq)) {
1886*4882a593Smuzhiyun pr_err("First context failed to start\n");
1887*4882a593Smuzhiyun goto err_wedged;
1888*4882a593Smuzhiyun }
1889*4882a593Smuzhiyun
1890*4882a593Smuzhiyun rq = spinner_create_request(&spin_hi, ctx_hi, engine,
1891*4882a593Smuzhiyun MI_NOOP);
1892*4882a593Smuzhiyun if (IS_ERR(rq)) {
1893*4882a593Smuzhiyun igt_spinner_end(&spin_lo);
1894*4882a593Smuzhiyun err = PTR_ERR(rq);
1895*4882a593Smuzhiyun goto err_ctx_lo;
1896*4882a593Smuzhiyun }
1897*4882a593Smuzhiyun
1898*4882a593Smuzhiyun i915_request_add(rq);
1899*4882a593Smuzhiyun if (igt_wait_for_spinner(&spin_hi, rq)) {
1900*4882a593Smuzhiyun pr_err("Second context overtook first?\n");
1901*4882a593Smuzhiyun goto err_wedged;
1902*4882a593Smuzhiyun }
1903*4882a593Smuzhiyun
1904*4882a593Smuzhiyun attr.priority = I915_USER_PRIORITY(I915_PRIORITY_MAX);
1905*4882a593Smuzhiyun engine->schedule(rq, &attr);
1906*4882a593Smuzhiyun
1907*4882a593Smuzhiyun if (!igt_wait_for_spinner(&spin_hi, rq)) {
1908*4882a593Smuzhiyun pr_err("High priority context failed to preempt the low priority context\n");
1909*4882a593Smuzhiyun GEM_TRACE_DUMP();
1910*4882a593Smuzhiyun goto err_wedged;
1911*4882a593Smuzhiyun }
1912*4882a593Smuzhiyun
1913*4882a593Smuzhiyun igt_spinner_end(&spin_hi);
1914*4882a593Smuzhiyun igt_spinner_end(&spin_lo);
1915*4882a593Smuzhiyun
1916*4882a593Smuzhiyun if (igt_live_test_end(&t)) {
1917*4882a593Smuzhiyun err = -EIO;
1918*4882a593Smuzhiyun goto err_ctx_lo;
1919*4882a593Smuzhiyun }
1920*4882a593Smuzhiyun }
1921*4882a593Smuzhiyun
1922*4882a593Smuzhiyun err = 0;
1923*4882a593Smuzhiyun err_ctx_lo:
1924*4882a593Smuzhiyun kernel_context_close(ctx_lo);
1925*4882a593Smuzhiyun err_ctx_hi:
1926*4882a593Smuzhiyun kernel_context_close(ctx_hi);
1927*4882a593Smuzhiyun err_spin_lo:
1928*4882a593Smuzhiyun igt_spinner_fini(&spin_lo);
1929*4882a593Smuzhiyun err_spin_hi:
1930*4882a593Smuzhiyun igt_spinner_fini(&spin_hi);
1931*4882a593Smuzhiyun return err;
1932*4882a593Smuzhiyun
1933*4882a593Smuzhiyun err_wedged:
1934*4882a593Smuzhiyun igt_spinner_end(&spin_hi);
1935*4882a593Smuzhiyun igt_spinner_end(&spin_lo);
1936*4882a593Smuzhiyun intel_gt_set_wedged(gt);
1937*4882a593Smuzhiyun err = -EIO;
1938*4882a593Smuzhiyun goto err_ctx_lo;
1939*4882a593Smuzhiyun }
1940*4882a593Smuzhiyun
1941*4882a593Smuzhiyun struct preempt_client {
1942*4882a593Smuzhiyun struct igt_spinner spin;
1943*4882a593Smuzhiyun struct i915_gem_context *ctx;
1944*4882a593Smuzhiyun };
1945*4882a593Smuzhiyun
preempt_client_init(struct intel_gt * gt,struct preempt_client * c)1946*4882a593Smuzhiyun static int preempt_client_init(struct intel_gt *gt, struct preempt_client *c)
1947*4882a593Smuzhiyun {
1948*4882a593Smuzhiyun c->ctx = kernel_context(gt->i915);
1949*4882a593Smuzhiyun if (!c->ctx)
1950*4882a593Smuzhiyun return -ENOMEM;
1951*4882a593Smuzhiyun
1952*4882a593Smuzhiyun if (igt_spinner_init(&c->spin, gt))
1953*4882a593Smuzhiyun goto err_ctx;
1954*4882a593Smuzhiyun
1955*4882a593Smuzhiyun return 0;
1956*4882a593Smuzhiyun
1957*4882a593Smuzhiyun err_ctx:
1958*4882a593Smuzhiyun kernel_context_close(c->ctx);
1959*4882a593Smuzhiyun return -ENOMEM;
1960*4882a593Smuzhiyun }
1961*4882a593Smuzhiyun
preempt_client_fini(struct preempt_client * c)1962*4882a593Smuzhiyun static void preempt_client_fini(struct preempt_client *c)
1963*4882a593Smuzhiyun {
1964*4882a593Smuzhiyun igt_spinner_fini(&c->spin);
1965*4882a593Smuzhiyun kernel_context_close(c->ctx);
1966*4882a593Smuzhiyun }
1967*4882a593Smuzhiyun
live_nopreempt(void * arg)1968*4882a593Smuzhiyun static int live_nopreempt(void *arg)
1969*4882a593Smuzhiyun {
1970*4882a593Smuzhiyun struct intel_gt *gt = arg;
1971*4882a593Smuzhiyun struct intel_engine_cs *engine;
1972*4882a593Smuzhiyun struct preempt_client a, b;
1973*4882a593Smuzhiyun enum intel_engine_id id;
1974*4882a593Smuzhiyun int err = -ENOMEM;
1975*4882a593Smuzhiyun
1976*4882a593Smuzhiyun /*
1977*4882a593Smuzhiyun * Verify that we can disable preemption for an individual request
1978*4882a593Smuzhiyun * that may be being observed and not want to be interrupted.
1979*4882a593Smuzhiyun */
1980*4882a593Smuzhiyun
1981*4882a593Smuzhiyun if (!HAS_LOGICAL_RING_PREEMPTION(gt->i915))
1982*4882a593Smuzhiyun return 0;
1983*4882a593Smuzhiyun
1984*4882a593Smuzhiyun if (preempt_client_init(gt, &a))
1985*4882a593Smuzhiyun return -ENOMEM;
1986*4882a593Smuzhiyun if (preempt_client_init(gt, &b))
1987*4882a593Smuzhiyun goto err_client_a;
1988*4882a593Smuzhiyun b.ctx->sched.priority = I915_USER_PRIORITY(I915_PRIORITY_MAX);
1989*4882a593Smuzhiyun
1990*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
1991*4882a593Smuzhiyun struct i915_request *rq_a, *rq_b;
1992*4882a593Smuzhiyun
1993*4882a593Smuzhiyun if (!intel_engine_has_preemption(engine))
1994*4882a593Smuzhiyun continue;
1995*4882a593Smuzhiyun
1996*4882a593Smuzhiyun engine->execlists.preempt_hang.count = 0;
1997*4882a593Smuzhiyun
1998*4882a593Smuzhiyun rq_a = spinner_create_request(&a.spin,
1999*4882a593Smuzhiyun a.ctx, engine,
2000*4882a593Smuzhiyun MI_ARB_CHECK);
2001*4882a593Smuzhiyun if (IS_ERR(rq_a)) {
2002*4882a593Smuzhiyun err = PTR_ERR(rq_a);
2003*4882a593Smuzhiyun goto err_client_b;
2004*4882a593Smuzhiyun }
2005*4882a593Smuzhiyun
2006*4882a593Smuzhiyun /* Low priority client, but unpreemptable! */
2007*4882a593Smuzhiyun __set_bit(I915_FENCE_FLAG_NOPREEMPT, &rq_a->fence.flags);
2008*4882a593Smuzhiyun
2009*4882a593Smuzhiyun i915_request_add(rq_a);
2010*4882a593Smuzhiyun if (!igt_wait_for_spinner(&a.spin, rq_a)) {
2011*4882a593Smuzhiyun pr_err("First client failed to start\n");
2012*4882a593Smuzhiyun goto err_wedged;
2013*4882a593Smuzhiyun }
2014*4882a593Smuzhiyun
2015*4882a593Smuzhiyun rq_b = spinner_create_request(&b.spin,
2016*4882a593Smuzhiyun b.ctx, engine,
2017*4882a593Smuzhiyun MI_ARB_CHECK);
2018*4882a593Smuzhiyun if (IS_ERR(rq_b)) {
2019*4882a593Smuzhiyun err = PTR_ERR(rq_b);
2020*4882a593Smuzhiyun goto err_client_b;
2021*4882a593Smuzhiyun }
2022*4882a593Smuzhiyun
2023*4882a593Smuzhiyun i915_request_add(rq_b);
2024*4882a593Smuzhiyun
2025*4882a593Smuzhiyun /* B is much more important than A! (But A is unpreemptable.) */
2026*4882a593Smuzhiyun GEM_BUG_ON(rq_prio(rq_b) <= rq_prio(rq_a));
2027*4882a593Smuzhiyun
2028*4882a593Smuzhiyun /* Wait long enough for preemption and timeslicing */
2029*4882a593Smuzhiyun if (igt_wait_for_spinner(&b.spin, rq_b)) {
2030*4882a593Smuzhiyun pr_err("Second client started too early!\n");
2031*4882a593Smuzhiyun goto err_wedged;
2032*4882a593Smuzhiyun }
2033*4882a593Smuzhiyun
2034*4882a593Smuzhiyun igt_spinner_end(&a.spin);
2035*4882a593Smuzhiyun
2036*4882a593Smuzhiyun if (!igt_wait_for_spinner(&b.spin, rq_b)) {
2037*4882a593Smuzhiyun pr_err("Second client failed to start\n");
2038*4882a593Smuzhiyun goto err_wedged;
2039*4882a593Smuzhiyun }
2040*4882a593Smuzhiyun
2041*4882a593Smuzhiyun igt_spinner_end(&b.spin);
2042*4882a593Smuzhiyun
2043*4882a593Smuzhiyun if (engine->execlists.preempt_hang.count) {
2044*4882a593Smuzhiyun pr_err("Preemption recorded x%d; should have been suppressed!\n",
2045*4882a593Smuzhiyun engine->execlists.preempt_hang.count);
2046*4882a593Smuzhiyun err = -EINVAL;
2047*4882a593Smuzhiyun goto err_wedged;
2048*4882a593Smuzhiyun }
2049*4882a593Smuzhiyun
2050*4882a593Smuzhiyun if (igt_flush_test(gt->i915))
2051*4882a593Smuzhiyun goto err_wedged;
2052*4882a593Smuzhiyun }
2053*4882a593Smuzhiyun
2054*4882a593Smuzhiyun err = 0;
2055*4882a593Smuzhiyun err_client_b:
2056*4882a593Smuzhiyun preempt_client_fini(&b);
2057*4882a593Smuzhiyun err_client_a:
2058*4882a593Smuzhiyun preempt_client_fini(&a);
2059*4882a593Smuzhiyun return err;
2060*4882a593Smuzhiyun
2061*4882a593Smuzhiyun err_wedged:
2062*4882a593Smuzhiyun igt_spinner_end(&b.spin);
2063*4882a593Smuzhiyun igt_spinner_end(&a.spin);
2064*4882a593Smuzhiyun intel_gt_set_wedged(gt);
2065*4882a593Smuzhiyun err = -EIO;
2066*4882a593Smuzhiyun goto err_client_b;
2067*4882a593Smuzhiyun }
2068*4882a593Smuzhiyun
2069*4882a593Smuzhiyun struct live_preempt_cancel {
2070*4882a593Smuzhiyun struct intel_engine_cs *engine;
2071*4882a593Smuzhiyun struct preempt_client a, b;
2072*4882a593Smuzhiyun };
2073*4882a593Smuzhiyun
__cancel_active0(struct live_preempt_cancel * arg)2074*4882a593Smuzhiyun static int __cancel_active0(struct live_preempt_cancel *arg)
2075*4882a593Smuzhiyun {
2076*4882a593Smuzhiyun struct i915_request *rq;
2077*4882a593Smuzhiyun struct igt_live_test t;
2078*4882a593Smuzhiyun int err;
2079*4882a593Smuzhiyun
2080*4882a593Smuzhiyun /* Preempt cancel of ELSP0 */
2081*4882a593Smuzhiyun GEM_TRACE("%s(%s)\n", __func__, arg->engine->name);
2082*4882a593Smuzhiyun if (igt_live_test_begin(&t, arg->engine->i915,
2083*4882a593Smuzhiyun __func__, arg->engine->name))
2084*4882a593Smuzhiyun return -EIO;
2085*4882a593Smuzhiyun
2086*4882a593Smuzhiyun rq = spinner_create_request(&arg->a.spin,
2087*4882a593Smuzhiyun arg->a.ctx, arg->engine,
2088*4882a593Smuzhiyun MI_ARB_CHECK);
2089*4882a593Smuzhiyun if (IS_ERR(rq))
2090*4882a593Smuzhiyun return PTR_ERR(rq);
2091*4882a593Smuzhiyun
2092*4882a593Smuzhiyun clear_bit(CONTEXT_BANNED, &rq->context->flags);
2093*4882a593Smuzhiyun i915_request_get(rq);
2094*4882a593Smuzhiyun i915_request_add(rq);
2095*4882a593Smuzhiyun if (!igt_wait_for_spinner(&arg->a.spin, rq)) {
2096*4882a593Smuzhiyun err = -EIO;
2097*4882a593Smuzhiyun goto out;
2098*4882a593Smuzhiyun }
2099*4882a593Smuzhiyun
2100*4882a593Smuzhiyun intel_context_set_banned(rq->context);
2101*4882a593Smuzhiyun err = intel_engine_pulse(arg->engine);
2102*4882a593Smuzhiyun if (err)
2103*4882a593Smuzhiyun goto out;
2104*4882a593Smuzhiyun
2105*4882a593Smuzhiyun err = wait_for_reset(arg->engine, rq, HZ / 2);
2106*4882a593Smuzhiyun if (err) {
2107*4882a593Smuzhiyun pr_err("Cancelled inflight0 request did not reset\n");
2108*4882a593Smuzhiyun goto out;
2109*4882a593Smuzhiyun }
2110*4882a593Smuzhiyun
2111*4882a593Smuzhiyun out:
2112*4882a593Smuzhiyun i915_request_put(rq);
2113*4882a593Smuzhiyun if (igt_live_test_end(&t))
2114*4882a593Smuzhiyun err = -EIO;
2115*4882a593Smuzhiyun return err;
2116*4882a593Smuzhiyun }
2117*4882a593Smuzhiyun
__cancel_active1(struct live_preempt_cancel * arg)2118*4882a593Smuzhiyun static int __cancel_active1(struct live_preempt_cancel *arg)
2119*4882a593Smuzhiyun {
2120*4882a593Smuzhiyun struct i915_request *rq[2] = {};
2121*4882a593Smuzhiyun struct igt_live_test t;
2122*4882a593Smuzhiyun int err;
2123*4882a593Smuzhiyun
2124*4882a593Smuzhiyun /* Preempt cancel of ELSP1 */
2125*4882a593Smuzhiyun GEM_TRACE("%s(%s)\n", __func__, arg->engine->name);
2126*4882a593Smuzhiyun if (igt_live_test_begin(&t, arg->engine->i915,
2127*4882a593Smuzhiyun __func__, arg->engine->name))
2128*4882a593Smuzhiyun return -EIO;
2129*4882a593Smuzhiyun
2130*4882a593Smuzhiyun rq[0] = spinner_create_request(&arg->a.spin,
2131*4882a593Smuzhiyun arg->a.ctx, arg->engine,
2132*4882a593Smuzhiyun MI_NOOP); /* no preemption */
2133*4882a593Smuzhiyun if (IS_ERR(rq[0]))
2134*4882a593Smuzhiyun return PTR_ERR(rq[0]);
2135*4882a593Smuzhiyun
2136*4882a593Smuzhiyun clear_bit(CONTEXT_BANNED, &rq[0]->context->flags);
2137*4882a593Smuzhiyun i915_request_get(rq[0]);
2138*4882a593Smuzhiyun i915_request_add(rq[0]);
2139*4882a593Smuzhiyun if (!igt_wait_for_spinner(&arg->a.spin, rq[0])) {
2140*4882a593Smuzhiyun err = -EIO;
2141*4882a593Smuzhiyun goto out;
2142*4882a593Smuzhiyun }
2143*4882a593Smuzhiyun
2144*4882a593Smuzhiyun rq[1] = spinner_create_request(&arg->b.spin,
2145*4882a593Smuzhiyun arg->b.ctx, arg->engine,
2146*4882a593Smuzhiyun MI_ARB_CHECK);
2147*4882a593Smuzhiyun if (IS_ERR(rq[1])) {
2148*4882a593Smuzhiyun err = PTR_ERR(rq[1]);
2149*4882a593Smuzhiyun goto out;
2150*4882a593Smuzhiyun }
2151*4882a593Smuzhiyun
2152*4882a593Smuzhiyun clear_bit(CONTEXT_BANNED, &rq[1]->context->flags);
2153*4882a593Smuzhiyun i915_request_get(rq[1]);
2154*4882a593Smuzhiyun err = i915_request_await_dma_fence(rq[1], &rq[0]->fence);
2155*4882a593Smuzhiyun i915_request_add(rq[1]);
2156*4882a593Smuzhiyun if (err)
2157*4882a593Smuzhiyun goto out;
2158*4882a593Smuzhiyun
2159*4882a593Smuzhiyun intel_context_set_banned(rq[1]->context);
2160*4882a593Smuzhiyun err = intel_engine_pulse(arg->engine);
2161*4882a593Smuzhiyun if (err)
2162*4882a593Smuzhiyun goto out;
2163*4882a593Smuzhiyun
2164*4882a593Smuzhiyun igt_spinner_end(&arg->a.spin);
2165*4882a593Smuzhiyun err = wait_for_reset(arg->engine, rq[1], HZ / 2);
2166*4882a593Smuzhiyun if (err)
2167*4882a593Smuzhiyun goto out;
2168*4882a593Smuzhiyun
2169*4882a593Smuzhiyun if (rq[0]->fence.error != 0) {
2170*4882a593Smuzhiyun pr_err("Normal inflight0 request did not complete\n");
2171*4882a593Smuzhiyun err = -EINVAL;
2172*4882a593Smuzhiyun goto out;
2173*4882a593Smuzhiyun }
2174*4882a593Smuzhiyun
2175*4882a593Smuzhiyun if (rq[1]->fence.error != -EIO) {
2176*4882a593Smuzhiyun pr_err("Cancelled inflight1 request did not report -EIO\n");
2177*4882a593Smuzhiyun err = -EINVAL;
2178*4882a593Smuzhiyun goto out;
2179*4882a593Smuzhiyun }
2180*4882a593Smuzhiyun
2181*4882a593Smuzhiyun out:
2182*4882a593Smuzhiyun i915_request_put(rq[1]);
2183*4882a593Smuzhiyun i915_request_put(rq[0]);
2184*4882a593Smuzhiyun if (igt_live_test_end(&t))
2185*4882a593Smuzhiyun err = -EIO;
2186*4882a593Smuzhiyun return err;
2187*4882a593Smuzhiyun }
2188*4882a593Smuzhiyun
__cancel_queued(struct live_preempt_cancel * arg)2189*4882a593Smuzhiyun static int __cancel_queued(struct live_preempt_cancel *arg)
2190*4882a593Smuzhiyun {
2191*4882a593Smuzhiyun struct i915_request *rq[3] = {};
2192*4882a593Smuzhiyun struct igt_live_test t;
2193*4882a593Smuzhiyun int err;
2194*4882a593Smuzhiyun
2195*4882a593Smuzhiyun /* Full ELSP and one in the wings */
2196*4882a593Smuzhiyun GEM_TRACE("%s(%s)\n", __func__, arg->engine->name);
2197*4882a593Smuzhiyun if (igt_live_test_begin(&t, arg->engine->i915,
2198*4882a593Smuzhiyun __func__, arg->engine->name))
2199*4882a593Smuzhiyun return -EIO;
2200*4882a593Smuzhiyun
2201*4882a593Smuzhiyun rq[0] = spinner_create_request(&arg->a.spin,
2202*4882a593Smuzhiyun arg->a.ctx, arg->engine,
2203*4882a593Smuzhiyun MI_ARB_CHECK);
2204*4882a593Smuzhiyun if (IS_ERR(rq[0]))
2205*4882a593Smuzhiyun return PTR_ERR(rq[0]);
2206*4882a593Smuzhiyun
2207*4882a593Smuzhiyun clear_bit(CONTEXT_BANNED, &rq[0]->context->flags);
2208*4882a593Smuzhiyun i915_request_get(rq[0]);
2209*4882a593Smuzhiyun i915_request_add(rq[0]);
2210*4882a593Smuzhiyun if (!igt_wait_for_spinner(&arg->a.spin, rq[0])) {
2211*4882a593Smuzhiyun err = -EIO;
2212*4882a593Smuzhiyun goto out;
2213*4882a593Smuzhiyun }
2214*4882a593Smuzhiyun
2215*4882a593Smuzhiyun rq[1] = igt_request_alloc(arg->b.ctx, arg->engine);
2216*4882a593Smuzhiyun if (IS_ERR(rq[1])) {
2217*4882a593Smuzhiyun err = PTR_ERR(rq[1]);
2218*4882a593Smuzhiyun goto out;
2219*4882a593Smuzhiyun }
2220*4882a593Smuzhiyun
2221*4882a593Smuzhiyun clear_bit(CONTEXT_BANNED, &rq[1]->context->flags);
2222*4882a593Smuzhiyun i915_request_get(rq[1]);
2223*4882a593Smuzhiyun err = i915_request_await_dma_fence(rq[1], &rq[0]->fence);
2224*4882a593Smuzhiyun i915_request_add(rq[1]);
2225*4882a593Smuzhiyun if (err)
2226*4882a593Smuzhiyun goto out;
2227*4882a593Smuzhiyun
2228*4882a593Smuzhiyun rq[2] = spinner_create_request(&arg->b.spin,
2229*4882a593Smuzhiyun arg->a.ctx, arg->engine,
2230*4882a593Smuzhiyun MI_ARB_CHECK);
2231*4882a593Smuzhiyun if (IS_ERR(rq[2])) {
2232*4882a593Smuzhiyun err = PTR_ERR(rq[2]);
2233*4882a593Smuzhiyun goto out;
2234*4882a593Smuzhiyun }
2235*4882a593Smuzhiyun
2236*4882a593Smuzhiyun i915_request_get(rq[2]);
2237*4882a593Smuzhiyun err = i915_request_await_dma_fence(rq[2], &rq[1]->fence);
2238*4882a593Smuzhiyun i915_request_add(rq[2]);
2239*4882a593Smuzhiyun if (err)
2240*4882a593Smuzhiyun goto out;
2241*4882a593Smuzhiyun
2242*4882a593Smuzhiyun intel_context_set_banned(rq[2]->context);
2243*4882a593Smuzhiyun err = intel_engine_pulse(arg->engine);
2244*4882a593Smuzhiyun if (err)
2245*4882a593Smuzhiyun goto out;
2246*4882a593Smuzhiyun
2247*4882a593Smuzhiyun err = wait_for_reset(arg->engine, rq[2], HZ / 2);
2248*4882a593Smuzhiyun if (err)
2249*4882a593Smuzhiyun goto out;
2250*4882a593Smuzhiyun
2251*4882a593Smuzhiyun if (rq[0]->fence.error != -EIO) {
2252*4882a593Smuzhiyun pr_err("Cancelled inflight0 request did not report -EIO\n");
2253*4882a593Smuzhiyun err = -EINVAL;
2254*4882a593Smuzhiyun goto out;
2255*4882a593Smuzhiyun }
2256*4882a593Smuzhiyun
2257*4882a593Smuzhiyun if (rq[1]->fence.error != 0) {
2258*4882a593Smuzhiyun pr_err("Normal inflight1 request did not complete\n");
2259*4882a593Smuzhiyun err = -EINVAL;
2260*4882a593Smuzhiyun goto out;
2261*4882a593Smuzhiyun }
2262*4882a593Smuzhiyun
2263*4882a593Smuzhiyun if (rq[2]->fence.error != -EIO) {
2264*4882a593Smuzhiyun pr_err("Cancelled queued request did not report -EIO\n");
2265*4882a593Smuzhiyun err = -EINVAL;
2266*4882a593Smuzhiyun goto out;
2267*4882a593Smuzhiyun }
2268*4882a593Smuzhiyun
2269*4882a593Smuzhiyun out:
2270*4882a593Smuzhiyun i915_request_put(rq[2]);
2271*4882a593Smuzhiyun i915_request_put(rq[1]);
2272*4882a593Smuzhiyun i915_request_put(rq[0]);
2273*4882a593Smuzhiyun if (igt_live_test_end(&t))
2274*4882a593Smuzhiyun err = -EIO;
2275*4882a593Smuzhiyun return err;
2276*4882a593Smuzhiyun }
2277*4882a593Smuzhiyun
__cancel_hostile(struct live_preempt_cancel * arg)2278*4882a593Smuzhiyun static int __cancel_hostile(struct live_preempt_cancel *arg)
2279*4882a593Smuzhiyun {
2280*4882a593Smuzhiyun struct i915_request *rq;
2281*4882a593Smuzhiyun int err;
2282*4882a593Smuzhiyun
2283*4882a593Smuzhiyun /* Preempt cancel non-preemptible spinner in ELSP0 */
2284*4882a593Smuzhiyun if (!IS_ACTIVE(CONFIG_DRM_I915_PREEMPT_TIMEOUT))
2285*4882a593Smuzhiyun return 0;
2286*4882a593Smuzhiyun
2287*4882a593Smuzhiyun if (!intel_has_reset_engine(arg->engine->gt))
2288*4882a593Smuzhiyun return 0;
2289*4882a593Smuzhiyun
2290*4882a593Smuzhiyun GEM_TRACE("%s(%s)\n", __func__, arg->engine->name);
2291*4882a593Smuzhiyun rq = spinner_create_request(&arg->a.spin,
2292*4882a593Smuzhiyun arg->a.ctx, arg->engine,
2293*4882a593Smuzhiyun MI_NOOP); /* preemption disabled */
2294*4882a593Smuzhiyun if (IS_ERR(rq))
2295*4882a593Smuzhiyun return PTR_ERR(rq);
2296*4882a593Smuzhiyun
2297*4882a593Smuzhiyun clear_bit(CONTEXT_BANNED, &rq->context->flags);
2298*4882a593Smuzhiyun i915_request_get(rq);
2299*4882a593Smuzhiyun i915_request_add(rq);
2300*4882a593Smuzhiyun if (!igt_wait_for_spinner(&arg->a.spin, rq)) {
2301*4882a593Smuzhiyun err = -EIO;
2302*4882a593Smuzhiyun goto out;
2303*4882a593Smuzhiyun }
2304*4882a593Smuzhiyun
2305*4882a593Smuzhiyun intel_context_set_banned(rq->context);
2306*4882a593Smuzhiyun err = intel_engine_pulse(arg->engine); /* force reset */
2307*4882a593Smuzhiyun if (err)
2308*4882a593Smuzhiyun goto out;
2309*4882a593Smuzhiyun
2310*4882a593Smuzhiyun err = wait_for_reset(arg->engine, rq, HZ / 2);
2311*4882a593Smuzhiyun if (err) {
2312*4882a593Smuzhiyun pr_err("Cancelled inflight0 request did not reset\n");
2313*4882a593Smuzhiyun goto out;
2314*4882a593Smuzhiyun }
2315*4882a593Smuzhiyun
2316*4882a593Smuzhiyun out:
2317*4882a593Smuzhiyun i915_request_put(rq);
2318*4882a593Smuzhiyun if (igt_flush_test(arg->engine->i915))
2319*4882a593Smuzhiyun err = -EIO;
2320*4882a593Smuzhiyun return err;
2321*4882a593Smuzhiyun }
2322*4882a593Smuzhiyun
live_preempt_cancel(void * arg)2323*4882a593Smuzhiyun static int live_preempt_cancel(void *arg)
2324*4882a593Smuzhiyun {
2325*4882a593Smuzhiyun struct intel_gt *gt = arg;
2326*4882a593Smuzhiyun struct live_preempt_cancel data;
2327*4882a593Smuzhiyun enum intel_engine_id id;
2328*4882a593Smuzhiyun int err = -ENOMEM;
2329*4882a593Smuzhiyun
2330*4882a593Smuzhiyun /*
2331*4882a593Smuzhiyun * To cancel an inflight context, we need to first remove it from the
2332*4882a593Smuzhiyun * GPU. That sounds like preemption! Plus a little bit of bookkeeping.
2333*4882a593Smuzhiyun */
2334*4882a593Smuzhiyun
2335*4882a593Smuzhiyun if (!HAS_LOGICAL_RING_PREEMPTION(gt->i915))
2336*4882a593Smuzhiyun return 0;
2337*4882a593Smuzhiyun
2338*4882a593Smuzhiyun if (preempt_client_init(gt, &data.a))
2339*4882a593Smuzhiyun return -ENOMEM;
2340*4882a593Smuzhiyun if (preempt_client_init(gt, &data.b))
2341*4882a593Smuzhiyun goto err_client_a;
2342*4882a593Smuzhiyun
2343*4882a593Smuzhiyun for_each_engine(data.engine, gt, id) {
2344*4882a593Smuzhiyun if (!intel_engine_has_preemption(data.engine))
2345*4882a593Smuzhiyun continue;
2346*4882a593Smuzhiyun
2347*4882a593Smuzhiyun err = __cancel_active0(&data);
2348*4882a593Smuzhiyun if (err)
2349*4882a593Smuzhiyun goto err_wedged;
2350*4882a593Smuzhiyun
2351*4882a593Smuzhiyun err = __cancel_active1(&data);
2352*4882a593Smuzhiyun if (err)
2353*4882a593Smuzhiyun goto err_wedged;
2354*4882a593Smuzhiyun
2355*4882a593Smuzhiyun err = __cancel_queued(&data);
2356*4882a593Smuzhiyun if (err)
2357*4882a593Smuzhiyun goto err_wedged;
2358*4882a593Smuzhiyun
2359*4882a593Smuzhiyun err = __cancel_hostile(&data);
2360*4882a593Smuzhiyun if (err)
2361*4882a593Smuzhiyun goto err_wedged;
2362*4882a593Smuzhiyun }
2363*4882a593Smuzhiyun
2364*4882a593Smuzhiyun err = 0;
2365*4882a593Smuzhiyun err_client_b:
2366*4882a593Smuzhiyun preempt_client_fini(&data.b);
2367*4882a593Smuzhiyun err_client_a:
2368*4882a593Smuzhiyun preempt_client_fini(&data.a);
2369*4882a593Smuzhiyun return err;
2370*4882a593Smuzhiyun
2371*4882a593Smuzhiyun err_wedged:
2372*4882a593Smuzhiyun GEM_TRACE_DUMP();
2373*4882a593Smuzhiyun igt_spinner_end(&data.b.spin);
2374*4882a593Smuzhiyun igt_spinner_end(&data.a.spin);
2375*4882a593Smuzhiyun intel_gt_set_wedged(gt);
2376*4882a593Smuzhiyun goto err_client_b;
2377*4882a593Smuzhiyun }
2378*4882a593Smuzhiyun
live_suppress_self_preempt(void * arg)2379*4882a593Smuzhiyun static int live_suppress_self_preempt(void *arg)
2380*4882a593Smuzhiyun {
2381*4882a593Smuzhiyun struct intel_gt *gt = arg;
2382*4882a593Smuzhiyun struct intel_engine_cs *engine;
2383*4882a593Smuzhiyun struct i915_sched_attr attr = {
2384*4882a593Smuzhiyun .priority = I915_USER_PRIORITY(I915_PRIORITY_MAX)
2385*4882a593Smuzhiyun };
2386*4882a593Smuzhiyun struct preempt_client a, b;
2387*4882a593Smuzhiyun enum intel_engine_id id;
2388*4882a593Smuzhiyun int err = -ENOMEM;
2389*4882a593Smuzhiyun
2390*4882a593Smuzhiyun /*
2391*4882a593Smuzhiyun * Verify that if a preemption request does not cause a change in
2392*4882a593Smuzhiyun * the current execution order, the preempt-to-idle injection is
2393*4882a593Smuzhiyun * skipped and that we do not accidentally apply it after the CS
2394*4882a593Smuzhiyun * completion event.
2395*4882a593Smuzhiyun */
2396*4882a593Smuzhiyun
2397*4882a593Smuzhiyun if (!HAS_LOGICAL_RING_PREEMPTION(gt->i915))
2398*4882a593Smuzhiyun return 0;
2399*4882a593Smuzhiyun
2400*4882a593Smuzhiyun if (intel_uc_uses_guc_submission(>->uc))
2401*4882a593Smuzhiyun return 0; /* presume black blox */
2402*4882a593Smuzhiyun
2403*4882a593Smuzhiyun if (intel_vgpu_active(gt->i915))
2404*4882a593Smuzhiyun return 0; /* GVT forces single port & request submission */
2405*4882a593Smuzhiyun
2406*4882a593Smuzhiyun if (preempt_client_init(gt, &a))
2407*4882a593Smuzhiyun return -ENOMEM;
2408*4882a593Smuzhiyun if (preempt_client_init(gt, &b))
2409*4882a593Smuzhiyun goto err_client_a;
2410*4882a593Smuzhiyun
2411*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
2412*4882a593Smuzhiyun struct i915_request *rq_a, *rq_b;
2413*4882a593Smuzhiyun int depth;
2414*4882a593Smuzhiyun
2415*4882a593Smuzhiyun if (!intel_engine_has_preemption(engine))
2416*4882a593Smuzhiyun continue;
2417*4882a593Smuzhiyun
2418*4882a593Smuzhiyun if (igt_flush_test(gt->i915))
2419*4882a593Smuzhiyun goto err_wedged;
2420*4882a593Smuzhiyun
2421*4882a593Smuzhiyun st_engine_heartbeat_disable(engine);
2422*4882a593Smuzhiyun engine->execlists.preempt_hang.count = 0;
2423*4882a593Smuzhiyun
2424*4882a593Smuzhiyun rq_a = spinner_create_request(&a.spin,
2425*4882a593Smuzhiyun a.ctx, engine,
2426*4882a593Smuzhiyun MI_NOOP);
2427*4882a593Smuzhiyun if (IS_ERR(rq_a)) {
2428*4882a593Smuzhiyun err = PTR_ERR(rq_a);
2429*4882a593Smuzhiyun st_engine_heartbeat_enable(engine);
2430*4882a593Smuzhiyun goto err_client_b;
2431*4882a593Smuzhiyun }
2432*4882a593Smuzhiyun
2433*4882a593Smuzhiyun i915_request_add(rq_a);
2434*4882a593Smuzhiyun if (!igt_wait_for_spinner(&a.spin, rq_a)) {
2435*4882a593Smuzhiyun pr_err("First client failed to start\n");
2436*4882a593Smuzhiyun st_engine_heartbeat_enable(engine);
2437*4882a593Smuzhiyun goto err_wedged;
2438*4882a593Smuzhiyun }
2439*4882a593Smuzhiyun
2440*4882a593Smuzhiyun /* Keep postponing the timer to avoid premature slicing */
2441*4882a593Smuzhiyun mod_timer(&engine->execlists.timer, jiffies + HZ);
2442*4882a593Smuzhiyun for (depth = 0; depth < 8; depth++) {
2443*4882a593Smuzhiyun rq_b = spinner_create_request(&b.spin,
2444*4882a593Smuzhiyun b.ctx, engine,
2445*4882a593Smuzhiyun MI_NOOP);
2446*4882a593Smuzhiyun if (IS_ERR(rq_b)) {
2447*4882a593Smuzhiyun err = PTR_ERR(rq_b);
2448*4882a593Smuzhiyun st_engine_heartbeat_enable(engine);
2449*4882a593Smuzhiyun goto err_client_b;
2450*4882a593Smuzhiyun }
2451*4882a593Smuzhiyun i915_request_add(rq_b);
2452*4882a593Smuzhiyun
2453*4882a593Smuzhiyun GEM_BUG_ON(i915_request_completed(rq_a));
2454*4882a593Smuzhiyun engine->schedule(rq_a, &attr);
2455*4882a593Smuzhiyun igt_spinner_end(&a.spin);
2456*4882a593Smuzhiyun
2457*4882a593Smuzhiyun if (!igt_wait_for_spinner(&b.spin, rq_b)) {
2458*4882a593Smuzhiyun pr_err("Second client failed to start\n");
2459*4882a593Smuzhiyun st_engine_heartbeat_enable(engine);
2460*4882a593Smuzhiyun goto err_wedged;
2461*4882a593Smuzhiyun }
2462*4882a593Smuzhiyun
2463*4882a593Smuzhiyun swap(a, b);
2464*4882a593Smuzhiyun rq_a = rq_b;
2465*4882a593Smuzhiyun }
2466*4882a593Smuzhiyun igt_spinner_end(&a.spin);
2467*4882a593Smuzhiyun
2468*4882a593Smuzhiyun if (engine->execlists.preempt_hang.count) {
2469*4882a593Smuzhiyun pr_err("Preemption on %s recorded x%d, depth %d; should have been suppressed!\n",
2470*4882a593Smuzhiyun engine->name,
2471*4882a593Smuzhiyun engine->execlists.preempt_hang.count,
2472*4882a593Smuzhiyun depth);
2473*4882a593Smuzhiyun st_engine_heartbeat_enable(engine);
2474*4882a593Smuzhiyun err = -EINVAL;
2475*4882a593Smuzhiyun goto err_client_b;
2476*4882a593Smuzhiyun }
2477*4882a593Smuzhiyun
2478*4882a593Smuzhiyun st_engine_heartbeat_enable(engine);
2479*4882a593Smuzhiyun if (igt_flush_test(gt->i915))
2480*4882a593Smuzhiyun goto err_wedged;
2481*4882a593Smuzhiyun }
2482*4882a593Smuzhiyun
2483*4882a593Smuzhiyun err = 0;
2484*4882a593Smuzhiyun err_client_b:
2485*4882a593Smuzhiyun preempt_client_fini(&b);
2486*4882a593Smuzhiyun err_client_a:
2487*4882a593Smuzhiyun preempt_client_fini(&a);
2488*4882a593Smuzhiyun return err;
2489*4882a593Smuzhiyun
2490*4882a593Smuzhiyun err_wedged:
2491*4882a593Smuzhiyun igt_spinner_end(&b.spin);
2492*4882a593Smuzhiyun igt_spinner_end(&a.spin);
2493*4882a593Smuzhiyun intel_gt_set_wedged(gt);
2494*4882a593Smuzhiyun err = -EIO;
2495*4882a593Smuzhiyun goto err_client_b;
2496*4882a593Smuzhiyun }
2497*4882a593Smuzhiyun
live_chain_preempt(void * arg)2498*4882a593Smuzhiyun static int live_chain_preempt(void *arg)
2499*4882a593Smuzhiyun {
2500*4882a593Smuzhiyun struct intel_gt *gt = arg;
2501*4882a593Smuzhiyun struct intel_engine_cs *engine;
2502*4882a593Smuzhiyun struct preempt_client hi, lo;
2503*4882a593Smuzhiyun enum intel_engine_id id;
2504*4882a593Smuzhiyun int err = -ENOMEM;
2505*4882a593Smuzhiyun
2506*4882a593Smuzhiyun /*
2507*4882a593Smuzhiyun * Build a chain AB...BA between two contexts (A, B) and request
2508*4882a593Smuzhiyun * preemption of the last request. It should then complete before
2509*4882a593Smuzhiyun * the previously submitted spinner in B.
2510*4882a593Smuzhiyun */
2511*4882a593Smuzhiyun
2512*4882a593Smuzhiyun if (!HAS_LOGICAL_RING_PREEMPTION(gt->i915))
2513*4882a593Smuzhiyun return 0;
2514*4882a593Smuzhiyun
2515*4882a593Smuzhiyun if (preempt_client_init(gt, &hi))
2516*4882a593Smuzhiyun return -ENOMEM;
2517*4882a593Smuzhiyun
2518*4882a593Smuzhiyun if (preempt_client_init(gt, &lo))
2519*4882a593Smuzhiyun goto err_client_hi;
2520*4882a593Smuzhiyun
2521*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
2522*4882a593Smuzhiyun struct i915_sched_attr attr = {
2523*4882a593Smuzhiyun .priority = I915_USER_PRIORITY(I915_PRIORITY_MAX),
2524*4882a593Smuzhiyun };
2525*4882a593Smuzhiyun struct igt_live_test t;
2526*4882a593Smuzhiyun struct i915_request *rq;
2527*4882a593Smuzhiyun int ring_size, count, i;
2528*4882a593Smuzhiyun
2529*4882a593Smuzhiyun if (!intel_engine_has_preemption(engine))
2530*4882a593Smuzhiyun continue;
2531*4882a593Smuzhiyun
2532*4882a593Smuzhiyun rq = spinner_create_request(&lo.spin,
2533*4882a593Smuzhiyun lo.ctx, engine,
2534*4882a593Smuzhiyun MI_ARB_CHECK);
2535*4882a593Smuzhiyun if (IS_ERR(rq))
2536*4882a593Smuzhiyun goto err_wedged;
2537*4882a593Smuzhiyun
2538*4882a593Smuzhiyun i915_request_get(rq);
2539*4882a593Smuzhiyun i915_request_add(rq);
2540*4882a593Smuzhiyun
2541*4882a593Smuzhiyun ring_size = rq->wa_tail - rq->head;
2542*4882a593Smuzhiyun if (ring_size < 0)
2543*4882a593Smuzhiyun ring_size += rq->ring->size;
2544*4882a593Smuzhiyun ring_size = rq->ring->size / ring_size;
2545*4882a593Smuzhiyun pr_debug("%s(%s): Using maximum of %d requests\n",
2546*4882a593Smuzhiyun __func__, engine->name, ring_size);
2547*4882a593Smuzhiyun
2548*4882a593Smuzhiyun igt_spinner_end(&lo.spin);
2549*4882a593Smuzhiyun if (i915_request_wait(rq, 0, HZ / 2) < 0) {
2550*4882a593Smuzhiyun pr_err("Timed out waiting to flush %s\n", engine->name);
2551*4882a593Smuzhiyun i915_request_put(rq);
2552*4882a593Smuzhiyun goto err_wedged;
2553*4882a593Smuzhiyun }
2554*4882a593Smuzhiyun i915_request_put(rq);
2555*4882a593Smuzhiyun
2556*4882a593Smuzhiyun if (igt_live_test_begin(&t, gt->i915, __func__, engine->name)) {
2557*4882a593Smuzhiyun err = -EIO;
2558*4882a593Smuzhiyun goto err_wedged;
2559*4882a593Smuzhiyun }
2560*4882a593Smuzhiyun
2561*4882a593Smuzhiyun for_each_prime_number_from(count, 1, ring_size) {
2562*4882a593Smuzhiyun rq = spinner_create_request(&hi.spin,
2563*4882a593Smuzhiyun hi.ctx, engine,
2564*4882a593Smuzhiyun MI_ARB_CHECK);
2565*4882a593Smuzhiyun if (IS_ERR(rq))
2566*4882a593Smuzhiyun goto err_wedged;
2567*4882a593Smuzhiyun i915_request_add(rq);
2568*4882a593Smuzhiyun if (!igt_wait_for_spinner(&hi.spin, rq))
2569*4882a593Smuzhiyun goto err_wedged;
2570*4882a593Smuzhiyun
2571*4882a593Smuzhiyun rq = spinner_create_request(&lo.spin,
2572*4882a593Smuzhiyun lo.ctx, engine,
2573*4882a593Smuzhiyun MI_ARB_CHECK);
2574*4882a593Smuzhiyun if (IS_ERR(rq))
2575*4882a593Smuzhiyun goto err_wedged;
2576*4882a593Smuzhiyun i915_request_add(rq);
2577*4882a593Smuzhiyun
2578*4882a593Smuzhiyun for (i = 0; i < count; i++) {
2579*4882a593Smuzhiyun rq = igt_request_alloc(lo.ctx, engine);
2580*4882a593Smuzhiyun if (IS_ERR(rq))
2581*4882a593Smuzhiyun goto err_wedged;
2582*4882a593Smuzhiyun i915_request_add(rq);
2583*4882a593Smuzhiyun }
2584*4882a593Smuzhiyun
2585*4882a593Smuzhiyun rq = igt_request_alloc(hi.ctx, engine);
2586*4882a593Smuzhiyun if (IS_ERR(rq))
2587*4882a593Smuzhiyun goto err_wedged;
2588*4882a593Smuzhiyun
2589*4882a593Smuzhiyun i915_request_get(rq);
2590*4882a593Smuzhiyun i915_request_add(rq);
2591*4882a593Smuzhiyun engine->schedule(rq, &attr);
2592*4882a593Smuzhiyun
2593*4882a593Smuzhiyun igt_spinner_end(&hi.spin);
2594*4882a593Smuzhiyun if (i915_request_wait(rq, 0, HZ / 5) < 0) {
2595*4882a593Smuzhiyun struct drm_printer p =
2596*4882a593Smuzhiyun drm_info_printer(gt->i915->drm.dev);
2597*4882a593Smuzhiyun
2598*4882a593Smuzhiyun pr_err("Failed to preempt over chain of %d\n",
2599*4882a593Smuzhiyun count);
2600*4882a593Smuzhiyun intel_engine_dump(engine, &p,
2601*4882a593Smuzhiyun "%s\n", engine->name);
2602*4882a593Smuzhiyun i915_request_put(rq);
2603*4882a593Smuzhiyun goto err_wedged;
2604*4882a593Smuzhiyun }
2605*4882a593Smuzhiyun igt_spinner_end(&lo.spin);
2606*4882a593Smuzhiyun i915_request_put(rq);
2607*4882a593Smuzhiyun
2608*4882a593Smuzhiyun rq = igt_request_alloc(lo.ctx, engine);
2609*4882a593Smuzhiyun if (IS_ERR(rq))
2610*4882a593Smuzhiyun goto err_wedged;
2611*4882a593Smuzhiyun
2612*4882a593Smuzhiyun i915_request_get(rq);
2613*4882a593Smuzhiyun i915_request_add(rq);
2614*4882a593Smuzhiyun
2615*4882a593Smuzhiyun if (i915_request_wait(rq, 0, HZ / 5) < 0) {
2616*4882a593Smuzhiyun struct drm_printer p =
2617*4882a593Smuzhiyun drm_info_printer(gt->i915->drm.dev);
2618*4882a593Smuzhiyun
2619*4882a593Smuzhiyun pr_err("Failed to flush low priority chain of %d requests\n",
2620*4882a593Smuzhiyun count);
2621*4882a593Smuzhiyun intel_engine_dump(engine, &p,
2622*4882a593Smuzhiyun "%s\n", engine->name);
2623*4882a593Smuzhiyun
2624*4882a593Smuzhiyun i915_request_put(rq);
2625*4882a593Smuzhiyun goto err_wedged;
2626*4882a593Smuzhiyun }
2627*4882a593Smuzhiyun i915_request_put(rq);
2628*4882a593Smuzhiyun }
2629*4882a593Smuzhiyun
2630*4882a593Smuzhiyun if (igt_live_test_end(&t)) {
2631*4882a593Smuzhiyun err = -EIO;
2632*4882a593Smuzhiyun goto err_wedged;
2633*4882a593Smuzhiyun }
2634*4882a593Smuzhiyun }
2635*4882a593Smuzhiyun
2636*4882a593Smuzhiyun err = 0;
2637*4882a593Smuzhiyun err_client_lo:
2638*4882a593Smuzhiyun preempt_client_fini(&lo);
2639*4882a593Smuzhiyun err_client_hi:
2640*4882a593Smuzhiyun preempt_client_fini(&hi);
2641*4882a593Smuzhiyun return err;
2642*4882a593Smuzhiyun
2643*4882a593Smuzhiyun err_wedged:
2644*4882a593Smuzhiyun igt_spinner_end(&hi.spin);
2645*4882a593Smuzhiyun igt_spinner_end(&lo.spin);
2646*4882a593Smuzhiyun intel_gt_set_wedged(gt);
2647*4882a593Smuzhiyun err = -EIO;
2648*4882a593Smuzhiyun goto err_client_lo;
2649*4882a593Smuzhiyun }
2650*4882a593Smuzhiyun
create_gang(struct intel_engine_cs * engine,struct i915_request ** prev)2651*4882a593Smuzhiyun static int create_gang(struct intel_engine_cs *engine,
2652*4882a593Smuzhiyun struct i915_request **prev)
2653*4882a593Smuzhiyun {
2654*4882a593Smuzhiyun struct drm_i915_gem_object *obj;
2655*4882a593Smuzhiyun struct intel_context *ce;
2656*4882a593Smuzhiyun struct i915_request *rq;
2657*4882a593Smuzhiyun struct i915_vma *vma;
2658*4882a593Smuzhiyun u32 *cs;
2659*4882a593Smuzhiyun int err;
2660*4882a593Smuzhiyun
2661*4882a593Smuzhiyun ce = intel_context_create(engine);
2662*4882a593Smuzhiyun if (IS_ERR(ce))
2663*4882a593Smuzhiyun return PTR_ERR(ce);
2664*4882a593Smuzhiyun
2665*4882a593Smuzhiyun obj = i915_gem_object_create_internal(engine->i915, 4096);
2666*4882a593Smuzhiyun if (IS_ERR(obj)) {
2667*4882a593Smuzhiyun err = PTR_ERR(obj);
2668*4882a593Smuzhiyun goto err_ce;
2669*4882a593Smuzhiyun }
2670*4882a593Smuzhiyun
2671*4882a593Smuzhiyun vma = i915_vma_instance(obj, ce->vm, NULL);
2672*4882a593Smuzhiyun if (IS_ERR(vma)) {
2673*4882a593Smuzhiyun err = PTR_ERR(vma);
2674*4882a593Smuzhiyun goto err_obj;
2675*4882a593Smuzhiyun }
2676*4882a593Smuzhiyun
2677*4882a593Smuzhiyun err = i915_vma_pin(vma, 0, 0, PIN_USER);
2678*4882a593Smuzhiyun if (err)
2679*4882a593Smuzhiyun goto err_obj;
2680*4882a593Smuzhiyun
2681*4882a593Smuzhiyun cs = i915_gem_object_pin_map(obj, I915_MAP_WC);
2682*4882a593Smuzhiyun if (IS_ERR(cs))
2683*4882a593Smuzhiyun goto err_obj;
2684*4882a593Smuzhiyun
2685*4882a593Smuzhiyun /* Semaphore target: spin until zero */
2686*4882a593Smuzhiyun *cs++ = MI_ARB_ON_OFF | MI_ARB_ENABLE;
2687*4882a593Smuzhiyun
2688*4882a593Smuzhiyun *cs++ = MI_SEMAPHORE_WAIT |
2689*4882a593Smuzhiyun MI_SEMAPHORE_POLL |
2690*4882a593Smuzhiyun MI_SEMAPHORE_SAD_EQ_SDD;
2691*4882a593Smuzhiyun *cs++ = 0;
2692*4882a593Smuzhiyun *cs++ = lower_32_bits(vma->node.start);
2693*4882a593Smuzhiyun *cs++ = upper_32_bits(vma->node.start);
2694*4882a593Smuzhiyun
2695*4882a593Smuzhiyun if (*prev) {
2696*4882a593Smuzhiyun u64 offset = (*prev)->batch->node.start;
2697*4882a593Smuzhiyun
2698*4882a593Smuzhiyun /* Terminate the spinner in the next lower priority batch. */
2699*4882a593Smuzhiyun *cs++ = MI_STORE_DWORD_IMM_GEN4;
2700*4882a593Smuzhiyun *cs++ = lower_32_bits(offset);
2701*4882a593Smuzhiyun *cs++ = upper_32_bits(offset);
2702*4882a593Smuzhiyun *cs++ = 0;
2703*4882a593Smuzhiyun }
2704*4882a593Smuzhiyun
2705*4882a593Smuzhiyun *cs++ = MI_BATCH_BUFFER_END;
2706*4882a593Smuzhiyun i915_gem_object_flush_map(obj);
2707*4882a593Smuzhiyun i915_gem_object_unpin_map(obj);
2708*4882a593Smuzhiyun
2709*4882a593Smuzhiyun rq = intel_context_create_request(ce);
2710*4882a593Smuzhiyun if (IS_ERR(rq))
2711*4882a593Smuzhiyun goto err_obj;
2712*4882a593Smuzhiyun
2713*4882a593Smuzhiyun rq->batch = i915_vma_get(vma);
2714*4882a593Smuzhiyun i915_request_get(rq);
2715*4882a593Smuzhiyun
2716*4882a593Smuzhiyun i915_vma_lock(vma);
2717*4882a593Smuzhiyun err = i915_request_await_object(rq, vma->obj, false);
2718*4882a593Smuzhiyun if (!err)
2719*4882a593Smuzhiyun err = i915_vma_move_to_active(vma, rq, 0);
2720*4882a593Smuzhiyun if (!err)
2721*4882a593Smuzhiyun err = rq->engine->emit_bb_start(rq,
2722*4882a593Smuzhiyun vma->node.start,
2723*4882a593Smuzhiyun PAGE_SIZE, 0);
2724*4882a593Smuzhiyun i915_vma_unlock(vma);
2725*4882a593Smuzhiyun i915_request_add(rq);
2726*4882a593Smuzhiyun if (err)
2727*4882a593Smuzhiyun goto err_rq;
2728*4882a593Smuzhiyun
2729*4882a593Smuzhiyun i915_gem_object_put(obj);
2730*4882a593Smuzhiyun intel_context_put(ce);
2731*4882a593Smuzhiyun
2732*4882a593Smuzhiyun rq->mock.link.next = &(*prev)->mock.link;
2733*4882a593Smuzhiyun *prev = rq;
2734*4882a593Smuzhiyun return 0;
2735*4882a593Smuzhiyun
2736*4882a593Smuzhiyun err_rq:
2737*4882a593Smuzhiyun i915_vma_put(rq->batch);
2738*4882a593Smuzhiyun i915_request_put(rq);
2739*4882a593Smuzhiyun err_obj:
2740*4882a593Smuzhiyun i915_gem_object_put(obj);
2741*4882a593Smuzhiyun err_ce:
2742*4882a593Smuzhiyun intel_context_put(ce);
2743*4882a593Smuzhiyun return err;
2744*4882a593Smuzhiyun }
2745*4882a593Smuzhiyun
__live_preempt_ring(struct intel_engine_cs * engine,struct igt_spinner * spin,int queue_sz,int ring_sz)2746*4882a593Smuzhiyun static int __live_preempt_ring(struct intel_engine_cs *engine,
2747*4882a593Smuzhiyun struct igt_spinner *spin,
2748*4882a593Smuzhiyun int queue_sz, int ring_sz)
2749*4882a593Smuzhiyun {
2750*4882a593Smuzhiyun struct intel_context *ce[2] = {};
2751*4882a593Smuzhiyun struct i915_request *rq;
2752*4882a593Smuzhiyun struct igt_live_test t;
2753*4882a593Smuzhiyun int err = 0;
2754*4882a593Smuzhiyun int n;
2755*4882a593Smuzhiyun
2756*4882a593Smuzhiyun if (igt_live_test_begin(&t, engine->i915, __func__, engine->name))
2757*4882a593Smuzhiyun return -EIO;
2758*4882a593Smuzhiyun
2759*4882a593Smuzhiyun for (n = 0; n < ARRAY_SIZE(ce); n++) {
2760*4882a593Smuzhiyun struct intel_context *tmp;
2761*4882a593Smuzhiyun
2762*4882a593Smuzhiyun tmp = intel_context_create(engine);
2763*4882a593Smuzhiyun if (IS_ERR(tmp)) {
2764*4882a593Smuzhiyun err = PTR_ERR(tmp);
2765*4882a593Smuzhiyun goto err_ce;
2766*4882a593Smuzhiyun }
2767*4882a593Smuzhiyun
2768*4882a593Smuzhiyun tmp->ring = __intel_context_ring_size(ring_sz);
2769*4882a593Smuzhiyun
2770*4882a593Smuzhiyun err = intel_context_pin(tmp);
2771*4882a593Smuzhiyun if (err) {
2772*4882a593Smuzhiyun intel_context_put(tmp);
2773*4882a593Smuzhiyun goto err_ce;
2774*4882a593Smuzhiyun }
2775*4882a593Smuzhiyun
2776*4882a593Smuzhiyun memset32(tmp->ring->vaddr,
2777*4882a593Smuzhiyun 0xdeadbeef, /* trigger a hang if executed */
2778*4882a593Smuzhiyun tmp->ring->vma->size / sizeof(u32));
2779*4882a593Smuzhiyun
2780*4882a593Smuzhiyun ce[n] = tmp;
2781*4882a593Smuzhiyun }
2782*4882a593Smuzhiyun
2783*4882a593Smuzhiyun rq = igt_spinner_create_request(spin, ce[0], MI_ARB_CHECK);
2784*4882a593Smuzhiyun if (IS_ERR(rq)) {
2785*4882a593Smuzhiyun err = PTR_ERR(rq);
2786*4882a593Smuzhiyun goto err_ce;
2787*4882a593Smuzhiyun }
2788*4882a593Smuzhiyun
2789*4882a593Smuzhiyun i915_request_get(rq);
2790*4882a593Smuzhiyun rq->sched.attr.priority = I915_PRIORITY_BARRIER;
2791*4882a593Smuzhiyun i915_request_add(rq);
2792*4882a593Smuzhiyun
2793*4882a593Smuzhiyun if (!igt_wait_for_spinner(spin, rq)) {
2794*4882a593Smuzhiyun intel_gt_set_wedged(engine->gt);
2795*4882a593Smuzhiyun i915_request_put(rq);
2796*4882a593Smuzhiyun err = -ETIME;
2797*4882a593Smuzhiyun goto err_ce;
2798*4882a593Smuzhiyun }
2799*4882a593Smuzhiyun
2800*4882a593Smuzhiyun /* Fill the ring, until we will cause a wrap */
2801*4882a593Smuzhiyun n = 0;
2802*4882a593Smuzhiyun while (ce[0]->ring->tail - rq->wa_tail <= queue_sz) {
2803*4882a593Smuzhiyun struct i915_request *tmp;
2804*4882a593Smuzhiyun
2805*4882a593Smuzhiyun tmp = intel_context_create_request(ce[0]);
2806*4882a593Smuzhiyun if (IS_ERR(tmp)) {
2807*4882a593Smuzhiyun err = PTR_ERR(tmp);
2808*4882a593Smuzhiyun i915_request_put(rq);
2809*4882a593Smuzhiyun goto err_ce;
2810*4882a593Smuzhiyun }
2811*4882a593Smuzhiyun
2812*4882a593Smuzhiyun i915_request_add(tmp);
2813*4882a593Smuzhiyun intel_engine_flush_submission(engine);
2814*4882a593Smuzhiyun n++;
2815*4882a593Smuzhiyun }
2816*4882a593Smuzhiyun intel_engine_flush_submission(engine);
2817*4882a593Smuzhiyun pr_debug("%s: Filled %d with %d nop tails {size:%x, tail:%x, emit:%x, rq.tail:%x}\n",
2818*4882a593Smuzhiyun engine->name, queue_sz, n,
2819*4882a593Smuzhiyun ce[0]->ring->size,
2820*4882a593Smuzhiyun ce[0]->ring->tail,
2821*4882a593Smuzhiyun ce[0]->ring->emit,
2822*4882a593Smuzhiyun rq->tail);
2823*4882a593Smuzhiyun i915_request_put(rq);
2824*4882a593Smuzhiyun
2825*4882a593Smuzhiyun /* Create a second request to preempt the first ring */
2826*4882a593Smuzhiyun rq = intel_context_create_request(ce[1]);
2827*4882a593Smuzhiyun if (IS_ERR(rq)) {
2828*4882a593Smuzhiyun err = PTR_ERR(rq);
2829*4882a593Smuzhiyun goto err_ce;
2830*4882a593Smuzhiyun }
2831*4882a593Smuzhiyun
2832*4882a593Smuzhiyun rq->sched.attr.priority = I915_PRIORITY_BARRIER;
2833*4882a593Smuzhiyun i915_request_get(rq);
2834*4882a593Smuzhiyun i915_request_add(rq);
2835*4882a593Smuzhiyun
2836*4882a593Smuzhiyun err = wait_for_submit(engine, rq, HZ / 2);
2837*4882a593Smuzhiyun i915_request_put(rq);
2838*4882a593Smuzhiyun if (err) {
2839*4882a593Smuzhiyun pr_err("%s: preemption request was not submited\n",
2840*4882a593Smuzhiyun engine->name);
2841*4882a593Smuzhiyun err = -ETIME;
2842*4882a593Smuzhiyun }
2843*4882a593Smuzhiyun
2844*4882a593Smuzhiyun pr_debug("%s: ring[0]:{ tail:%x, emit:%x }, ring[1]:{ tail:%x, emit:%x }\n",
2845*4882a593Smuzhiyun engine->name,
2846*4882a593Smuzhiyun ce[0]->ring->tail, ce[0]->ring->emit,
2847*4882a593Smuzhiyun ce[1]->ring->tail, ce[1]->ring->emit);
2848*4882a593Smuzhiyun
2849*4882a593Smuzhiyun err_ce:
2850*4882a593Smuzhiyun intel_engine_flush_submission(engine);
2851*4882a593Smuzhiyun igt_spinner_end(spin);
2852*4882a593Smuzhiyun for (n = 0; n < ARRAY_SIZE(ce); n++) {
2853*4882a593Smuzhiyun if (IS_ERR_OR_NULL(ce[n]))
2854*4882a593Smuzhiyun break;
2855*4882a593Smuzhiyun
2856*4882a593Smuzhiyun intel_context_unpin(ce[n]);
2857*4882a593Smuzhiyun intel_context_put(ce[n]);
2858*4882a593Smuzhiyun }
2859*4882a593Smuzhiyun if (igt_live_test_end(&t))
2860*4882a593Smuzhiyun err = -EIO;
2861*4882a593Smuzhiyun return err;
2862*4882a593Smuzhiyun }
2863*4882a593Smuzhiyun
live_preempt_ring(void * arg)2864*4882a593Smuzhiyun static int live_preempt_ring(void *arg)
2865*4882a593Smuzhiyun {
2866*4882a593Smuzhiyun struct intel_gt *gt = arg;
2867*4882a593Smuzhiyun struct intel_engine_cs *engine;
2868*4882a593Smuzhiyun struct igt_spinner spin;
2869*4882a593Smuzhiyun enum intel_engine_id id;
2870*4882a593Smuzhiyun int err = 0;
2871*4882a593Smuzhiyun
2872*4882a593Smuzhiyun /*
2873*4882a593Smuzhiyun * Check that we rollback large chunks of a ring in order to do a
2874*4882a593Smuzhiyun * preemption event. Similar to live_unlite_ring, but looking at
2875*4882a593Smuzhiyun * ring size rather than the impact of intel_ring_direction().
2876*4882a593Smuzhiyun */
2877*4882a593Smuzhiyun
2878*4882a593Smuzhiyun if (igt_spinner_init(&spin, gt))
2879*4882a593Smuzhiyun return -ENOMEM;
2880*4882a593Smuzhiyun
2881*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
2882*4882a593Smuzhiyun int n;
2883*4882a593Smuzhiyun
2884*4882a593Smuzhiyun if (!intel_engine_has_preemption(engine))
2885*4882a593Smuzhiyun continue;
2886*4882a593Smuzhiyun
2887*4882a593Smuzhiyun if (!intel_engine_can_store_dword(engine))
2888*4882a593Smuzhiyun continue;
2889*4882a593Smuzhiyun
2890*4882a593Smuzhiyun st_engine_heartbeat_disable(engine);
2891*4882a593Smuzhiyun
2892*4882a593Smuzhiyun for (n = 0; n <= 3; n++) {
2893*4882a593Smuzhiyun err = __live_preempt_ring(engine, &spin,
2894*4882a593Smuzhiyun n * SZ_4K / 4, SZ_4K);
2895*4882a593Smuzhiyun if (err)
2896*4882a593Smuzhiyun break;
2897*4882a593Smuzhiyun }
2898*4882a593Smuzhiyun
2899*4882a593Smuzhiyun st_engine_heartbeat_enable(engine);
2900*4882a593Smuzhiyun if (err)
2901*4882a593Smuzhiyun break;
2902*4882a593Smuzhiyun }
2903*4882a593Smuzhiyun
2904*4882a593Smuzhiyun igt_spinner_fini(&spin);
2905*4882a593Smuzhiyun return err;
2906*4882a593Smuzhiyun }
2907*4882a593Smuzhiyun
live_preempt_gang(void * arg)2908*4882a593Smuzhiyun static int live_preempt_gang(void *arg)
2909*4882a593Smuzhiyun {
2910*4882a593Smuzhiyun struct intel_gt *gt = arg;
2911*4882a593Smuzhiyun struct intel_engine_cs *engine;
2912*4882a593Smuzhiyun enum intel_engine_id id;
2913*4882a593Smuzhiyun
2914*4882a593Smuzhiyun if (!HAS_LOGICAL_RING_PREEMPTION(gt->i915))
2915*4882a593Smuzhiyun return 0;
2916*4882a593Smuzhiyun
2917*4882a593Smuzhiyun /*
2918*4882a593Smuzhiyun * Build as long a chain of preempters as we can, with each
2919*4882a593Smuzhiyun * request higher priority than the last. Once we are ready, we release
2920*4882a593Smuzhiyun * the last batch which then precolates down the chain, each releasing
2921*4882a593Smuzhiyun * the next oldest in turn. The intent is to simply push as hard as we
2922*4882a593Smuzhiyun * can with the number of preemptions, trying to exceed narrow HW
2923*4882a593Smuzhiyun * limits. At a minimum, we insist that we can sort all the user
2924*4882a593Smuzhiyun * high priority levels into execution order.
2925*4882a593Smuzhiyun */
2926*4882a593Smuzhiyun
2927*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
2928*4882a593Smuzhiyun struct i915_request *rq = NULL;
2929*4882a593Smuzhiyun struct igt_live_test t;
2930*4882a593Smuzhiyun IGT_TIMEOUT(end_time);
2931*4882a593Smuzhiyun int prio = 0;
2932*4882a593Smuzhiyun int err = 0;
2933*4882a593Smuzhiyun u32 *cs;
2934*4882a593Smuzhiyun
2935*4882a593Smuzhiyun if (!intel_engine_has_preemption(engine))
2936*4882a593Smuzhiyun continue;
2937*4882a593Smuzhiyun
2938*4882a593Smuzhiyun if (igt_live_test_begin(&t, gt->i915, __func__, engine->name))
2939*4882a593Smuzhiyun return -EIO;
2940*4882a593Smuzhiyun
2941*4882a593Smuzhiyun do {
2942*4882a593Smuzhiyun struct i915_sched_attr attr = {
2943*4882a593Smuzhiyun .priority = I915_USER_PRIORITY(prio++),
2944*4882a593Smuzhiyun };
2945*4882a593Smuzhiyun
2946*4882a593Smuzhiyun err = create_gang(engine, &rq);
2947*4882a593Smuzhiyun if (err)
2948*4882a593Smuzhiyun break;
2949*4882a593Smuzhiyun
2950*4882a593Smuzhiyun /* Submit each spinner at increasing priority */
2951*4882a593Smuzhiyun engine->schedule(rq, &attr);
2952*4882a593Smuzhiyun } while (prio <= I915_PRIORITY_MAX &&
2953*4882a593Smuzhiyun !__igt_timeout(end_time, NULL));
2954*4882a593Smuzhiyun pr_debug("%s: Preempt chain of %d requests\n",
2955*4882a593Smuzhiyun engine->name, prio);
2956*4882a593Smuzhiyun
2957*4882a593Smuzhiyun /*
2958*4882a593Smuzhiyun * Such that the last spinner is the highest priority and
2959*4882a593Smuzhiyun * should execute first. When that spinner completes,
2960*4882a593Smuzhiyun * it will terminate the next lowest spinner until there
2961*4882a593Smuzhiyun * are no more spinners and the gang is complete.
2962*4882a593Smuzhiyun */
2963*4882a593Smuzhiyun cs = i915_gem_object_pin_map(rq->batch->obj, I915_MAP_WC);
2964*4882a593Smuzhiyun if (!IS_ERR(cs)) {
2965*4882a593Smuzhiyun *cs = 0;
2966*4882a593Smuzhiyun i915_gem_object_unpin_map(rq->batch->obj);
2967*4882a593Smuzhiyun } else {
2968*4882a593Smuzhiyun err = PTR_ERR(cs);
2969*4882a593Smuzhiyun intel_gt_set_wedged(gt);
2970*4882a593Smuzhiyun }
2971*4882a593Smuzhiyun
2972*4882a593Smuzhiyun while (rq) { /* wait for each rq from highest to lowest prio */
2973*4882a593Smuzhiyun struct i915_request *n = list_next_entry(rq, mock.link);
2974*4882a593Smuzhiyun
2975*4882a593Smuzhiyun if (err == 0 && i915_request_wait(rq, 0, HZ / 5) < 0) {
2976*4882a593Smuzhiyun struct drm_printer p =
2977*4882a593Smuzhiyun drm_info_printer(engine->i915->drm.dev);
2978*4882a593Smuzhiyun
2979*4882a593Smuzhiyun pr_err("Failed to flush chain of %d requests, at %d\n",
2980*4882a593Smuzhiyun prio, rq_prio(rq) >> I915_USER_PRIORITY_SHIFT);
2981*4882a593Smuzhiyun intel_engine_dump(engine, &p,
2982*4882a593Smuzhiyun "%s\n", engine->name);
2983*4882a593Smuzhiyun
2984*4882a593Smuzhiyun err = -ETIME;
2985*4882a593Smuzhiyun }
2986*4882a593Smuzhiyun
2987*4882a593Smuzhiyun i915_vma_put(rq->batch);
2988*4882a593Smuzhiyun i915_request_put(rq);
2989*4882a593Smuzhiyun rq = n;
2990*4882a593Smuzhiyun }
2991*4882a593Smuzhiyun
2992*4882a593Smuzhiyun if (igt_live_test_end(&t))
2993*4882a593Smuzhiyun err = -EIO;
2994*4882a593Smuzhiyun if (err)
2995*4882a593Smuzhiyun return err;
2996*4882a593Smuzhiyun }
2997*4882a593Smuzhiyun
2998*4882a593Smuzhiyun return 0;
2999*4882a593Smuzhiyun }
3000*4882a593Smuzhiyun
3001*4882a593Smuzhiyun static struct i915_vma *
create_gpr_user(struct intel_engine_cs * engine,struct i915_vma * result,unsigned int offset)3002*4882a593Smuzhiyun create_gpr_user(struct intel_engine_cs *engine,
3003*4882a593Smuzhiyun struct i915_vma *result,
3004*4882a593Smuzhiyun unsigned int offset)
3005*4882a593Smuzhiyun {
3006*4882a593Smuzhiyun struct drm_i915_gem_object *obj;
3007*4882a593Smuzhiyun struct i915_vma *vma;
3008*4882a593Smuzhiyun u32 *cs;
3009*4882a593Smuzhiyun int err;
3010*4882a593Smuzhiyun int i;
3011*4882a593Smuzhiyun
3012*4882a593Smuzhiyun obj = i915_gem_object_create_internal(engine->i915, 4096);
3013*4882a593Smuzhiyun if (IS_ERR(obj))
3014*4882a593Smuzhiyun return ERR_CAST(obj);
3015*4882a593Smuzhiyun
3016*4882a593Smuzhiyun vma = i915_vma_instance(obj, result->vm, NULL);
3017*4882a593Smuzhiyun if (IS_ERR(vma)) {
3018*4882a593Smuzhiyun i915_gem_object_put(obj);
3019*4882a593Smuzhiyun return vma;
3020*4882a593Smuzhiyun }
3021*4882a593Smuzhiyun
3022*4882a593Smuzhiyun err = i915_vma_pin(vma, 0, 0, PIN_USER);
3023*4882a593Smuzhiyun if (err) {
3024*4882a593Smuzhiyun i915_vma_put(vma);
3025*4882a593Smuzhiyun return ERR_PTR(err);
3026*4882a593Smuzhiyun }
3027*4882a593Smuzhiyun
3028*4882a593Smuzhiyun cs = i915_gem_object_pin_map(obj, I915_MAP_WC);
3029*4882a593Smuzhiyun if (IS_ERR(cs)) {
3030*4882a593Smuzhiyun i915_vma_put(vma);
3031*4882a593Smuzhiyun return ERR_CAST(cs);
3032*4882a593Smuzhiyun }
3033*4882a593Smuzhiyun
3034*4882a593Smuzhiyun /* All GPR are clear for new contexts. We use GPR(0) as a constant */
3035*4882a593Smuzhiyun *cs++ = MI_LOAD_REGISTER_IMM(1);
3036*4882a593Smuzhiyun *cs++ = CS_GPR(engine, 0);
3037*4882a593Smuzhiyun *cs++ = 1;
3038*4882a593Smuzhiyun
3039*4882a593Smuzhiyun for (i = 1; i < NUM_GPR; i++) {
3040*4882a593Smuzhiyun u64 addr;
3041*4882a593Smuzhiyun
3042*4882a593Smuzhiyun /*
3043*4882a593Smuzhiyun * Perform: GPR[i]++
3044*4882a593Smuzhiyun *
3045*4882a593Smuzhiyun * As we read and write into the context saved GPR[i], if
3046*4882a593Smuzhiyun * we restart this batch buffer from an earlier point, we
3047*4882a593Smuzhiyun * will repeat the increment and store a value > 1.
3048*4882a593Smuzhiyun */
3049*4882a593Smuzhiyun *cs++ = MI_MATH(4);
3050*4882a593Smuzhiyun *cs++ = MI_MATH_LOAD(MI_MATH_REG_SRCA, MI_MATH_REG(i));
3051*4882a593Smuzhiyun *cs++ = MI_MATH_LOAD(MI_MATH_REG_SRCB, MI_MATH_REG(0));
3052*4882a593Smuzhiyun *cs++ = MI_MATH_ADD;
3053*4882a593Smuzhiyun *cs++ = MI_MATH_STORE(MI_MATH_REG(i), MI_MATH_REG_ACCU);
3054*4882a593Smuzhiyun
3055*4882a593Smuzhiyun addr = result->node.start + offset + i * sizeof(*cs);
3056*4882a593Smuzhiyun *cs++ = MI_STORE_REGISTER_MEM_GEN8;
3057*4882a593Smuzhiyun *cs++ = CS_GPR(engine, 2 * i);
3058*4882a593Smuzhiyun *cs++ = lower_32_bits(addr);
3059*4882a593Smuzhiyun *cs++ = upper_32_bits(addr);
3060*4882a593Smuzhiyun
3061*4882a593Smuzhiyun *cs++ = MI_SEMAPHORE_WAIT |
3062*4882a593Smuzhiyun MI_SEMAPHORE_POLL |
3063*4882a593Smuzhiyun MI_SEMAPHORE_SAD_GTE_SDD;
3064*4882a593Smuzhiyun *cs++ = i;
3065*4882a593Smuzhiyun *cs++ = lower_32_bits(result->node.start);
3066*4882a593Smuzhiyun *cs++ = upper_32_bits(result->node.start);
3067*4882a593Smuzhiyun }
3068*4882a593Smuzhiyun
3069*4882a593Smuzhiyun *cs++ = MI_BATCH_BUFFER_END;
3070*4882a593Smuzhiyun i915_gem_object_flush_map(obj);
3071*4882a593Smuzhiyun i915_gem_object_unpin_map(obj);
3072*4882a593Smuzhiyun
3073*4882a593Smuzhiyun return vma;
3074*4882a593Smuzhiyun }
3075*4882a593Smuzhiyun
create_global(struct intel_gt * gt,size_t sz)3076*4882a593Smuzhiyun static struct i915_vma *create_global(struct intel_gt *gt, size_t sz)
3077*4882a593Smuzhiyun {
3078*4882a593Smuzhiyun struct drm_i915_gem_object *obj;
3079*4882a593Smuzhiyun struct i915_vma *vma;
3080*4882a593Smuzhiyun int err;
3081*4882a593Smuzhiyun
3082*4882a593Smuzhiyun obj = i915_gem_object_create_internal(gt->i915, sz);
3083*4882a593Smuzhiyun if (IS_ERR(obj))
3084*4882a593Smuzhiyun return ERR_CAST(obj);
3085*4882a593Smuzhiyun
3086*4882a593Smuzhiyun vma = i915_vma_instance(obj, >->ggtt->vm, NULL);
3087*4882a593Smuzhiyun if (IS_ERR(vma)) {
3088*4882a593Smuzhiyun i915_gem_object_put(obj);
3089*4882a593Smuzhiyun return vma;
3090*4882a593Smuzhiyun }
3091*4882a593Smuzhiyun
3092*4882a593Smuzhiyun err = i915_ggtt_pin(vma, NULL, 0, 0);
3093*4882a593Smuzhiyun if (err) {
3094*4882a593Smuzhiyun i915_vma_put(vma);
3095*4882a593Smuzhiyun return ERR_PTR(err);
3096*4882a593Smuzhiyun }
3097*4882a593Smuzhiyun
3098*4882a593Smuzhiyun return vma;
3099*4882a593Smuzhiyun }
3100*4882a593Smuzhiyun
3101*4882a593Smuzhiyun static struct i915_request *
create_gpr_client(struct intel_engine_cs * engine,struct i915_vma * global,unsigned int offset)3102*4882a593Smuzhiyun create_gpr_client(struct intel_engine_cs *engine,
3103*4882a593Smuzhiyun struct i915_vma *global,
3104*4882a593Smuzhiyun unsigned int offset)
3105*4882a593Smuzhiyun {
3106*4882a593Smuzhiyun struct i915_vma *batch, *vma;
3107*4882a593Smuzhiyun struct intel_context *ce;
3108*4882a593Smuzhiyun struct i915_request *rq;
3109*4882a593Smuzhiyun int err;
3110*4882a593Smuzhiyun
3111*4882a593Smuzhiyun ce = intel_context_create(engine);
3112*4882a593Smuzhiyun if (IS_ERR(ce))
3113*4882a593Smuzhiyun return ERR_CAST(ce);
3114*4882a593Smuzhiyun
3115*4882a593Smuzhiyun vma = i915_vma_instance(global->obj, ce->vm, NULL);
3116*4882a593Smuzhiyun if (IS_ERR(vma)) {
3117*4882a593Smuzhiyun err = PTR_ERR(vma);
3118*4882a593Smuzhiyun goto out_ce;
3119*4882a593Smuzhiyun }
3120*4882a593Smuzhiyun
3121*4882a593Smuzhiyun err = i915_vma_pin(vma, 0, 0, PIN_USER);
3122*4882a593Smuzhiyun if (err)
3123*4882a593Smuzhiyun goto out_ce;
3124*4882a593Smuzhiyun
3125*4882a593Smuzhiyun batch = create_gpr_user(engine, vma, offset);
3126*4882a593Smuzhiyun if (IS_ERR(batch)) {
3127*4882a593Smuzhiyun err = PTR_ERR(batch);
3128*4882a593Smuzhiyun goto out_vma;
3129*4882a593Smuzhiyun }
3130*4882a593Smuzhiyun
3131*4882a593Smuzhiyun rq = intel_context_create_request(ce);
3132*4882a593Smuzhiyun if (IS_ERR(rq)) {
3133*4882a593Smuzhiyun err = PTR_ERR(rq);
3134*4882a593Smuzhiyun goto out_batch;
3135*4882a593Smuzhiyun }
3136*4882a593Smuzhiyun
3137*4882a593Smuzhiyun i915_vma_lock(vma);
3138*4882a593Smuzhiyun err = i915_request_await_object(rq, vma->obj, false);
3139*4882a593Smuzhiyun if (!err)
3140*4882a593Smuzhiyun err = i915_vma_move_to_active(vma, rq, 0);
3141*4882a593Smuzhiyun i915_vma_unlock(vma);
3142*4882a593Smuzhiyun
3143*4882a593Smuzhiyun i915_vma_lock(batch);
3144*4882a593Smuzhiyun if (!err)
3145*4882a593Smuzhiyun err = i915_request_await_object(rq, batch->obj, false);
3146*4882a593Smuzhiyun if (!err)
3147*4882a593Smuzhiyun err = i915_vma_move_to_active(batch, rq, 0);
3148*4882a593Smuzhiyun if (!err)
3149*4882a593Smuzhiyun err = rq->engine->emit_bb_start(rq,
3150*4882a593Smuzhiyun batch->node.start,
3151*4882a593Smuzhiyun PAGE_SIZE, 0);
3152*4882a593Smuzhiyun i915_vma_unlock(batch);
3153*4882a593Smuzhiyun i915_vma_unpin(batch);
3154*4882a593Smuzhiyun
3155*4882a593Smuzhiyun if (!err)
3156*4882a593Smuzhiyun i915_request_get(rq);
3157*4882a593Smuzhiyun i915_request_add(rq);
3158*4882a593Smuzhiyun
3159*4882a593Smuzhiyun out_batch:
3160*4882a593Smuzhiyun i915_vma_put(batch);
3161*4882a593Smuzhiyun out_vma:
3162*4882a593Smuzhiyun i915_vma_unpin(vma);
3163*4882a593Smuzhiyun out_ce:
3164*4882a593Smuzhiyun intel_context_put(ce);
3165*4882a593Smuzhiyun return err ? ERR_PTR(err) : rq;
3166*4882a593Smuzhiyun }
3167*4882a593Smuzhiyun
preempt_user(struct intel_engine_cs * engine,struct i915_vma * global,int id)3168*4882a593Smuzhiyun static int preempt_user(struct intel_engine_cs *engine,
3169*4882a593Smuzhiyun struct i915_vma *global,
3170*4882a593Smuzhiyun int id)
3171*4882a593Smuzhiyun {
3172*4882a593Smuzhiyun struct i915_sched_attr attr = {
3173*4882a593Smuzhiyun .priority = I915_PRIORITY_MAX
3174*4882a593Smuzhiyun };
3175*4882a593Smuzhiyun struct i915_request *rq;
3176*4882a593Smuzhiyun int err = 0;
3177*4882a593Smuzhiyun u32 *cs;
3178*4882a593Smuzhiyun
3179*4882a593Smuzhiyun rq = intel_engine_create_kernel_request(engine);
3180*4882a593Smuzhiyun if (IS_ERR(rq))
3181*4882a593Smuzhiyun return PTR_ERR(rq);
3182*4882a593Smuzhiyun
3183*4882a593Smuzhiyun cs = intel_ring_begin(rq, 4);
3184*4882a593Smuzhiyun if (IS_ERR(cs)) {
3185*4882a593Smuzhiyun i915_request_add(rq);
3186*4882a593Smuzhiyun return PTR_ERR(cs);
3187*4882a593Smuzhiyun }
3188*4882a593Smuzhiyun
3189*4882a593Smuzhiyun *cs++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
3190*4882a593Smuzhiyun *cs++ = i915_ggtt_offset(global);
3191*4882a593Smuzhiyun *cs++ = 0;
3192*4882a593Smuzhiyun *cs++ = id;
3193*4882a593Smuzhiyun
3194*4882a593Smuzhiyun intel_ring_advance(rq, cs);
3195*4882a593Smuzhiyun
3196*4882a593Smuzhiyun i915_request_get(rq);
3197*4882a593Smuzhiyun i915_request_add(rq);
3198*4882a593Smuzhiyun
3199*4882a593Smuzhiyun engine->schedule(rq, &attr);
3200*4882a593Smuzhiyun
3201*4882a593Smuzhiyun if (i915_request_wait(rq, 0, HZ / 2) < 0)
3202*4882a593Smuzhiyun err = -ETIME;
3203*4882a593Smuzhiyun i915_request_put(rq);
3204*4882a593Smuzhiyun
3205*4882a593Smuzhiyun return err;
3206*4882a593Smuzhiyun }
3207*4882a593Smuzhiyun
live_preempt_user(void * arg)3208*4882a593Smuzhiyun static int live_preempt_user(void *arg)
3209*4882a593Smuzhiyun {
3210*4882a593Smuzhiyun struct intel_gt *gt = arg;
3211*4882a593Smuzhiyun struct intel_engine_cs *engine;
3212*4882a593Smuzhiyun struct i915_vma *global;
3213*4882a593Smuzhiyun enum intel_engine_id id;
3214*4882a593Smuzhiyun u32 *result;
3215*4882a593Smuzhiyun int err = 0;
3216*4882a593Smuzhiyun
3217*4882a593Smuzhiyun if (!HAS_LOGICAL_RING_PREEMPTION(gt->i915))
3218*4882a593Smuzhiyun return 0;
3219*4882a593Smuzhiyun
3220*4882a593Smuzhiyun /*
3221*4882a593Smuzhiyun * In our other tests, we look at preemption in carefully
3222*4882a593Smuzhiyun * controlled conditions in the ringbuffer. Since most of the
3223*4882a593Smuzhiyun * time is spent in user batches, most of our preemptions naturally
3224*4882a593Smuzhiyun * occur there. We want to verify that when we preempt inside a batch
3225*4882a593Smuzhiyun * we continue on from the current instruction and do not roll back
3226*4882a593Smuzhiyun * to the start, or another earlier arbitration point.
3227*4882a593Smuzhiyun *
3228*4882a593Smuzhiyun * To verify this, we create a batch which is a mixture of
3229*4882a593Smuzhiyun * MI_MATH (gpr++) MI_SRM (gpr) and preemption points. Then with
3230*4882a593Smuzhiyun * a few preempting contexts thrown into the mix, we look for any
3231*4882a593Smuzhiyun * repeated instructions (which show up as incorrect values).
3232*4882a593Smuzhiyun */
3233*4882a593Smuzhiyun
3234*4882a593Smuzhiyun global = create_global(gt, 4096);
3235*4882a593Smuzhiyun if (IS_ERR(global))
3236*4882a593Smuzhiyun return PTR_ERR(global);
3237*4882a593Smuzhiyun
3238*4882a593Smuzhiyun result = i915_gem_object_pin_map(global->obj, I915_MAP_WC);
3239*4882a593Smuzhiyun if (IS_ERR(result)) {
3240*4882a593Smuzhiyun i915_vma_unpin_and_release(&global, 0);
3241*4882a593Smuzhiyun return PTR_ERR(result);
3242*4882a593Smuzhiyun }
3243*4882a593Smuzhiyun
3244*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
3245*4882a593Smuzhiyun struct i915_request *client[3] = {};
3246*4882a593Smuzhiyun struct igt_live_test t;
3247*4882a593Smuzhiyun int i;
3248*4882a593Smuzhiyun
3249*4882a593Smuzhiyun if (!intel_engine_has_preemption(engine))
3250*4882a593Smuzhiyun continue;
3251*4882a593Smuzhiyun
3252*4882a593Smuzhiyun if (IS_GEN(gt->i915, 8) && engine->class != RENDER_CLASS)
3253*4882a593Smuzhiyun continue; /* we need per-context GPR */
3254*4882a593Smuzhiyun
3255*4882a593Smuzhiyun if (igt_live_test_begin(&t, gt->i915, __func__, engine->name)) {
3256*4882a593Smuzhiyun err = -EIO;
3257*4882a593Smuzhiyun break;
3258*4882a593Smuzhiyun }
3259*4882a593Smuzhiyun
3260*4882a593Smuzhiyun memset(result, 0, 4096);
3261*4882a593Smuzhiyun
3262*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(client); i++) {
3263*4882a593Smuzhiyun struct i915_request *rq;
3264*4882a593Smuzhiyun
3265*4882a593Smuzhiyun rq = create_gpr_client(engine, global,
3266*4882a593Smuzhiyun NUM_GPR * i * sizeof(u32));
3267*4882a593Smuzhiyun if (IS_ERR(rq))
3268*4882a593Smuzhiyun goto end_test;
3269*4882a593Smuzhiyun
3270*4882a593Smuzhiyun client[i] = rq;
3271*4882a593Smuzhiyun }
3272*4882a593Smuzhiyun
3273*4882a593Smuzhiyun /* Continuously preempt the set of 3 running contexts */
3274*4882a593Smuzhiyun for (i = 1; i <= NUM_GPR; i++) {
3275*4882a593Smuzhiyun err = preempt_user(engine, global, i);
3276*4882a593Smuzhiyun if (err)
3277*4882a593Smuzhiyun goto end_test;
3278*4882a593Smuzhiyun }
3279*4882a593Smuzhiyun
3280*4882a593Smuzhiyun if (READ_ONCE(result[0]) != NUM_GPR) {
3281*4882a593Smuzhiyun pr_err("%s: Failed to release semaphore\n",
3282*4882a593Smuzhiyun engine->name);
3283*4882a593Smuzhiyun err = -EIO;
3284*4882a593Smuzhiyun goto end_test;
3285*4882a593Smuzhiyun }
3286*4882a593Smuzhiyun
3287*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(client); i++) {
3288*4882a593Smuzhiyun int gpr;
3289*4882a593Smuzhiyun
3290*4882a593Smuzhiyun if (i915_request_wait(client[i], 0, HZ / 2) < 0) {
3291*4882a593Smuzhiyun err = -ETIME;
3292*4882a593Smuzhiyun goto end_test;
3293*4882a593Smuzhiyun }
3294*4882a593Smuzhiyun
3295*4882a593Smuzhiyun for (gpr = 1; gpr < NUM_GPR; gpr++) {
3296*4882a593Smuzhiyun if (result[NUM_GPR * i + gpr] != 1) {
3297*4882a593Smuzhiyun pr_err("%s: Invalid result, client %d, gpr %d, result: %d\n",
3298*4882a593Smuzhiyun engine->name,
3299*4882a593Smuzhiyun i, gpr, result[NUM_GPR * i + gpr]);
3300*4882a593Smuzhiyun err = -EINVAL;
3301*4882a593Smuzhiyun goto end_test;
3302*4882a593Smuzhiyun }
3303*4882a593Smuzhiyun }
3304*4882a593Smuzhiyun }
3305*4882a593Smuzhiyun
3306*4882a593Smuzhiyun end_test:
3307*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(client); i++) {
3308*4882a593Smuzhiyun if (!client[i])
3309*4882a593Smuzhiyun break;
3310*4882a593Smuzhiyun
3311*4882a593Smuzhiyun i915_request_put(client[i]);
3312*4882a593Smuzhiyun }
3313*4882a593Smuzhiyun
3314*4882a593Smuzhiyun /* Flush the semaphores on error */
3315*4882a593Smuzhiyun smp_store_mb(result[0], -1);
3316*4882a593Smuzhiyun if (igt_live_test_end(&t))
3317*4882a593Smuzhiyun err = -EIO;
3318*4882a593Smuzhiyun if (err)
3319*4882a593Smuzhiyun break;
3320*4882a593Smuzhiyun }
3321*4882a593Smuzhiyun
3322*4882a593Smuzhiyun i915_vma_unpin_and_release(&global, I915_VMA_RELEASE_MAP);
3323*4882a593Smuzhiyun return err;
3324*4882a593Smuzhiyun }
3325*4882a593Smuzhiyun
live_preempt_timeout(void * arg)3326*4882a593Smuzhiyun static int live_preempt_timeout(void *arg)
3327*4882a593Smuzhiyun {
3328*4882a593Smuzhiyun struct intel_gt *gt = arg;
3329*4882a593Smuzhiyun struct i915_gem_context *ctx_hi, *ctx_lo;
3330*4882a593Smuzhiyun struct igt_spinner spin_lo;
3331*4882a593Smuzhiyun struct intel_engine_cs *engine;
3332*4882a593Smuzhiyun enum intel_engine_id id;
3333*4882a593Smuzhiyun int err = -ENOMEM;
3334*4882a593Smuzhiyun
3335*4882a593Smuzhiyun /*
3336*4882a593Smuzhiyun * Check that we force preemption to occur by cancelling the previous
3337*4882a593Smuzhiyun * context if it refuses to yield the GPU.
3338*4882a593Smuzhiyun */
3339*4882a593Smuzhiyun if (!IS_ACTIVE(CONFIG_DRM_I915_PREEMPT_TIMEOUT))
3340*4882a593Smuzhiyun return 0;
3341*4882a593Smuzhiyun
3342*4882a593Smuzhiyun if (!HAS_LOGICAL_RING_PREEMPTION(gt->i915))
3343*4882a593Smuzhiyun return 0;
3344*4882a593Smuzhiyun
3345*4882a593Smuzhiyun if (!intel_has_reset_engine(gt))
3346*4882a593Smuzhiyun return 0;
3347*4882a593Smuzhiyun
3348*4882a593Smuzhiyun if (igt_spinner_init(&spin_lo, gt))
3349*4882a593Smuzhiyun return -ENOMEM;
3350*4882a593Smuzhiyun
3351*4882a593Smuzhiyun ctx_hi = kernel_context(gt->i915);
3352*4882a593Smuzhiyun if (!ctx_hi)
3353*4882a593Smuzhiyun goto err_spin_lo;
3354*4882a593Smuzhiyun ctx_hi->sched.priority =
3355*4882a593Smuzhiyun I915_USER_PRIORITY(I915_CONTEXT_MAX_USER_PRIORITY);
3356*4882a593Smuzhiyun
3357*4882a593Smuzhiyun ctx_lo = kernel_context(gt->i915);
3358*4882a593Smuzhiyun if (!ctx_lo)
3359*4882a593Smuzhiyun goto err_ctx_hi;
3360*4882a593Smuzhiyun ctx_lo->sched.priority =
3361*4882a593Smuzhiyun I915_USER_PRIORITY(I915_CONTEXT_MIN_USER_PRIORITY);
3362*4882a593Smuzhiyun
3363*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
3364*4882a593Smuzhiyun unsigned long saved_timeout;
3365*4882a593Smuzhiyun struct i915_request *rq;
3366*4882a593Smuzhiyun
3367*4882a593Smuzhiyun if (!intel_engine_has_preemption(engine))
3368*4882a593Smuzhiyun continue;
3369*4882a593Smuzhiyun
3370*4882a593Smuzhiyun rq = spinner_create_request(&spin_lo, ctx_lo, engine,
3371*4882a593Smuzhiyun MI_NOOP); /* preemption disabled */
3372*4882a593Smuzhiyun if (IS_ERR(rq)) {
3373*4882a593Smuzhiyun err = PTR_ERR(rq);
3374*4882a593Smuzhiyun goto err_ctx_lo;
3375*4882a593Smuzhiyun }
3376*4882a593Smuzhiyun
3377*4882a593Smuzhiyun i915_request_add(rq);
3378*4882a593Smuzhiyun if (!igt_wait_for_spinner(&spin_lo, rq)) {
3379*4882a593Smuzhiyun intel_gt_set_wedged(gt);
3380*4882a593Smuzhiyun err = -EIO;
3381*4882a593Smuzhiyun goto err_ctx_lo;
3382*4882a593Smuzhiyun }
3383*4882a593Smuzhiyun
3384*4882a593Smuzhiyun rq = igt_request_alloc(ctx_hi, engine);
3385*4882a593Smuzhiyun if (IS_ERR(rq)) {
3386*4882a593Smuzhiyun igt_spinner_end(&spin_lo);
3387*4882a593Smuzhiyun err = PTR_ERR(rq);
3388*4882a593Smuzhiyun goto err_ctx_lo;
3389*4882a593Smuzhiyun }
3390*4882a593Smuzhiyun
3391*4882a593Smuzhiyun /* Flush the previous CS ack before changing timeouts */
3392*4882a593Smuzhiyun while (READ_ONCE(engine->execlists.pending[0]))
3393*4882a593Smuzhiyun cpu_relax();
3394*4882a593Smuzhiyun
3395*4882a593Smuzhiyun saved_timeout = engine->props.preempt_timeout_ms;
3396*4882a593Smuzhiyun engine->props.preempt_timeout_ms = 1; /* in ms, -> 1 jiffie */
3397*4882a593Smuzhiyun
3398*4882a593Smuzhiyun i915_request_get(rq);
3399*4882a593Smuzhiyun i915_request_add(rq);
3400*4882a593Smuzhiyun
3401*4882a593Smuzhiyun intel_engine_flush_submission(engine);
3402*4882a593Smuzhiyun engine->props.preempt_timeout_ms = saved_timeout;
3403*4882a593Smuzhiyun
3404*4882a593Smuzhiyun if (i915_request_wait(rq, 0, HZ / 10) < 0) {
3405*4882a593Smuzhiyun intel_gt_set_wedged(gt);
3406*4882a593Smuzhiyun i915_request_put(rq);
3407*4882a593Smuzhiyun err = -ETIME;
3408*4882a593Smuzhiyun goto err_ctx_lo;
3409*4882a593Smuzhiyun }
3410*4882a593Smuzhiyun
3411*4882a593Smuzhiyun igt_spinner_end(&spin_lo);
3412*4882a593Smuzhiyun i915_request_put(rq);
3413*4882a593Smuzhiyun }
3414*4882a593Smuzhiyun
3415*4882a593Smuzhiyun err = 0;
3416*4882a593Smuzhiyun err_ctx_lo:
3417*4882a593Smuzhiyun kernel_context_close(ctx_lo);
3418*4882a593Smuzhiyun err_ctx_hi:
3419*4882a593Smuzhiyun kernel_context_close(ctx_hi);
3420*4882a593Smuzhiyun err_spin_lo:
3421*4882a593Smuzhiyun igt_spinner_fini(&spin_lo);
3422*4882a593Smuzhiyun return err;
3423*4882a593Smuzhiyun }
3424*4882a593Smuzhiyun
random_range(struct rnd_state * rnd,int min,int max)3425*4882a593Smuzhiyun static int random_range(struct rnd_state *rnd, int min, int max)
3426*4882a593Smuzhiyun {
3427*4882a593Smuzhiyun return i915_prandom_u32_max_state(max - min, rnd) + min;
3428*4882a593Smuzhiyun }
3429*4882a593Smuzhiyun
random_priority(struct rnd_state * rnd)3430*4882a593Smuzhiyun static int random_priority(struct rnd_state *rnd)
3431*4882a593Smuzhiyun {
3432*4882a593Smuzhiyun return random_range(rnd, I915_PRIORITY_MIN, I915_PRIORITY_MAX);
3433*4882a593Smuzhiyun }
3434*4882a593Smuzhiyun
3435*4882a593Smuzhiyun struct preempt_smoke {
3436*4882a593Smuzhiyun struct intel_gt *gt;
3437*4882a593Smuzhiyun struct i915_gem_context **contexts;
3438*4882a593Smuzhiyun struct intel_engine_cs *engine;
3439*4882a593Smuzhiyun struct drm_i915_gem_object *batch;
3440*4882a593Smuzhiyun unsigned int ncontext;
3441*4882a593Smuzhiyun struct rnd_state prng;
3442*4882a593Smuzhiyun unsigned long count;
3443*4882a593Smuzhiyun };
3444*4882a593Smuzhiyun
smoke_context(struct preempt_smoke * smoke)3445*4882a593Smuzhiyun static struct i915_gem_context *smoke_context(struct preempt_smoke *smoke)
3446*4882a593Smuzhiyun {
3447*4882a593Smuzhiyun return smoke->contexts[i915_prandom_u32_max_state(smoke->ncontext,
3448*4882a593Smuzhiyun &smoke->prng)];
3449*4882a593Smuzhiyun }
3450*4882a593Smuzhiyun
smoke_submit(struct preempt_smoke * smoke,struct i915_gem_context * ctx,int prio,struct drm_i915_gem_object * batch)3451*4882a593Smuzhiyun static int smoke_submit(struct preempt_smoke *smoke,
3452*4882a593Smuzhiyun struct i915_gem_context *ctx, int prio,
3453*4882a593Smuzhiyun struct drm_i915_gem_object *batch)
3454*4882a593Smuzhiyun {
3455*4882a593Smuzhiyun struct i915_request *rq;
3456*4882a593Smuzhiyun struct i915_vma *vma = NULL;
3457*4882a593Smuzhiyun int err = 0;
3458*4882a593Smuzhiyun
3459*4882a593Smuzhiyun if (batch) {
3460*4882a593Smuzhiyun struct i915_address_space *vm;
3461*4882a593Smuzhiyun
3462*4882a593Smuzhiyun vm = i915_gem_context_get_vm_rcu(ctx);
3463*4882a593Smuzhiyun vma = i915_vma_instance(batch, vm, NULL);
3464*4882a593Smuzhiyun i915_vm_put(vm);
3465*4882a593Smuzhiyun if (IS_ERR(vma))
3466*4882a593Smuzhiyun return PTR_ERR(vma);
3467*4882a593Smuzhiyun
3468*4882a593Smuzhiyun err = i915_vma_pin(vma, 0, 0, PIN_USER);
3469*4882a593Smuzhiyun if (err)
3470*4882a593Smuzhiyun return err;
3471*4882a593Smuzhiyun }
3472*4882a593Smuzhiyun
3473*4882a593Smuzhiyun ctx->sched.priority = prio;
3474*4882a593Smuzhiyun
3475*4882a593Smuzhiyun rq = igt_request_alloc(ctx, smoke->engine);
3476*4882a593Smuzhiyun if (IS_ERR(rq)) {
3477*4882a593Smuzhiyun err = PTR_ERR(rq);
3478*4882a593Smuzhiyun goto unpin;
3479*4882a593Smuzhiyun }
3480*4882a593Smuzhiyun
3481*4882a593Smuzhiyun if (vma) {
3482*4882a593Smuzhiyun i915_vma_lock(vma);
3483*4882a593Smuzhiyun err = i915_request_await_object(rq, vma->obj, false);
3484*4882a593Smuzhiyun if (!err)
3485*4882a593Smuzhiyun err = i915_vma_move_to_active(vma, rq, 0);
3486*4882a593Smuzhiyun if (!err)
3487*4882a593Smuzhiyun err = rq->engine->emit_bb_start(rq,
3488*4882a593Smuzhiyun vma->node.start,
3489*4882a593Smuzhiyun PAGE_SIZE, 0);
3490*4882a593Smuzhiyun i915_vma_unlock(vma);
3491*4882a593Smuzhiyun }
3492*4882a593Smuzhiyun
3493*4882a593Smuzhiyun i915_request_add(rq);
3494*4882a593Smuzhiyun
3495*4882a593Smuzhiyun unpin:
3496*4882a593Smuzhiyun if (vma)
3497*4882a593Smuzhiyun i915_vma_unpin(vma);
3498*4882a593Smuzhiyun
3499*4882a593Smuzhiyun return err;
3500*4882a593Smuzhiyun }
3501*4882a593Smuzhiyun
smoke_crescendo_thread(void * arg)3502*4882a593Smuzhiyun static int smoke_crescendo_thread(void *arg)
3503*4882a593Smuzhiyun {
3504*4882a593Smuzhiyun struct preempt_smoke *smoke = arg;
3505*4882a593Smuzhiyun IGT_TIMEOUT(end_time);
3506*4882a593Smuzhiyun unsigned long count;
3507*4882a593Smuzhiyun
3508*4882a593Smuzhiyun count = 0;
3509*4882a593Smuzhiyun do {
3510*4882a593Smuzhiyun struct i915_gem_context *ctx = smoke_context(smoke);
3511*4882a593Smuzhiyun int err;
3512*4882a593Smuzhiyun
3513*4882a593Smuzhiyun err = smoke_submit(smoke,
3514*4882a593Smuzhiyun ctx, count % I915_PRIORITY_MAX,
3515*4882a593Smuzhiyun smoke->batch);
3516*4882a593Smuzhiyun if (err)
3517*4882a593Smuzhiyun return err;
3518*4882a593Smuzhiyun
3519*4882a593Smuzhiyun count++;
3520*4882a593Smuzhiyun } while (count < smoke->ncontext && !__igt_timeout(end_time, NULL));
3521*4882a593Smuzhiyun
3522*4882a593Smuzhiyun smoke->count = count;
3523*4882a593Smuzhiyun return 0;
3524*4882a593Smuzhiyun }
3525*4882a593Smuzhiyun
smoke_crescendo(struct preempt_smoke * smoke,unsigned int flags)3526*4882a593Smuzhiyun static int smoke_crescendo(struct preempt_smoke *smoke, unsigned int flags)
3527*4882a593Smuzhiyun #define BATCH BIT(0)
3528*4882a593Smuzhiyun {
3529*4882a593Smuzhiyun struct task_struct *tsk[I915_NUM_ENGINES] = {};
3530*4882a593Smuzhiyun struct preempt_smoke arg[I915_NUM_ENGINES];
3531*4882a593Smuzhiyun struct intel_engine_cs *engine;
3532*4882a593Smuzhiyun enum intel_engine_id id;
3533*4882a593Smuzhiyun unsigned long count;
3534*4882a593Smuzhiyun int err = 0;
3535*4882a593Smuzhiyun
3536*4882a593Smuzhiyun for_each_engine(engine, smoke->gt, id) {
3537*4882a593Smuzhiyun arg[id] = *smoke;
3538*4882a593Smuzhiyun arg[id].engine = engine;
3539*4882a593Smuzhiyun if (!(flags & BATCH))
3540*4882a593Smuzhiyun arg[id].batch = NULL;
3541*4882a593Smuzhiyun arg[id].count = 0;
3542*4882a593Smuzhiyun
3543*4882a593Smuzhiyun tsk[id] = kthread_run(smoke_crescendo_thread, &arg,
3544*4882a593Smuzhiyun "igt/smoke:%d", id);
3545*4882a593Smuzhiyun if (IS_ERR(tsk[id])) {
3546*4882a593Smuzhiyun err = PTR_ERR(tsk[id]);
3547*4882a593Smuzhiyun break;
3548*4882a593Smuzhiyun }
3549*4882a593Smuzhiyun get_task_struct(tsk[id]);
3550*4882a593Smuzhiyun }
3551*4882a593Smuzhiyun
3552*4882a593Smuzhiyun yield(); /* start all threads before we kthread_stop() */
3553*4882a593Smuzhiyun
3554*4882a593Smuzhiyun count = 0;
3555*4882a593Smuzhiyun for_each_engine(engine, smoke->gt, id) {
3556*4882a593Smuzhiyun int status;
3557*4882a593Smuzhiyun
3558*4882a593Smuzhiyun if (IS_ERR_OR_NULL(tsk[id]))
3559*4882a593Smuzhiyun continue;
3560*4882a593Smuzhiyun
3561*4882a593Smuzhiyun status = kthread_stop(tsk[id]);
3562*4882a593Smuzhiyun if (status && !err)
3563*4882a593Smuzhiyun err = status;
3564*4882a593Smuzhiyun
3565*4882a593Smuzhiyun count += arg[id].count;
3566*4882a593Smuzhiyun
3567*4882a593Smuzhiyun put_task_struct(tsk[id]);
3568*4882a593Smuzhiyun }
3569*4882a593Smuzhiyun
3570*4882a593Smuzhiyun pr_info("Submitted %lu crescendo:%x requests across %d engines and %d contexts\n",
3571*4882a593Smuzhiyun count, flags, smoke->gt->info.num_engines, smoke->ncontext);
3572*4882a593Smuzhiyun return 0;
3573*4882a593Smuzhiyun }
3574*4882a593Smuzhiyun
smoke_random(struct preempt_smoke * smoke,unsigned int flags)3575*4882a593Smuzhiyun static int smoke_random(struct preempt_smoke *smoke, unsigned int flags)
3576*4882a593Smuzhiyun {
3577*4882a593Smuzhiyun enum intel_engine_id id;
3578*4882a593Smuzhiyun IGT_TIMEOUT(end_time);
3579*4882a593Smuzhiyun unsigned long count;
3580*4882a593Smuzhiyun
3581*4882a593Smuzhiyun count = 0;
3582*4882a593Smuzhiyun do {
3583*4882a593Smuzhiyun for_each_engine(smoke->engine, smoke->gt, id) {
3584*4882a593Smuzhiyun struct i915_gem_context *ctx = smoke_context(smoke);
3585*4882a593Smuzhiyun int err;
3586*4882a593Smuzhiyun
3587*4882a593Smuzhiyun err = smoke_submit(smoke,
3588*4882a593Smuzhiyun ctx, random_priority(&smoke->prng),
3589*4882a593Smuzhiyun flags & BATCH ? smoke->batch : NULL);
3590*4882a593Smuzhiyun if (err)
3591*4882a593Smuzhiyun return err;
3592*4882a593Smuzhiyun
3593*4882a593Smuzhiyun count++;
3594*4882a593Smuzhiyun }
3595*4882a593Smuzhiyun } while (count < smoke->ncontext && !__igt_timeout(end_time, NULL));
3596*4882a593Smuzhiyun
3597*4882a593Smuzhiyun pr_info("Submitted %lu random:%x requests across %d engines and %d contexts\n",
3598*4882a593Smuzhiyun count, flags, smoke->gt->info.num_engines, smoke->ncontext);
3599*4882a593Smuzhiyun return 0;
3600*4882a593Smuzhiyun }
3601*4882a593Smuzhiyun
live_preempt_smoke(void * arg)3602*4882a593Smuzhiyun static int live_preempt_smoke(void *arg)
3603*4882a593Smuzhiyun {
3604*4882a593Smuzhiyun struct preempt_smoke smoke = {
3605*4882a593Smuzhiyun .gt = arg,
3606*4882a593Smuzhiyun .prng = I915_RND_STATE_INITIALIZER(i915_selftest.random_seed),
3607*4882a593Smuzhiyun .ncontext = 256,
3608*4882a593Smuzhiyun };
3609*4882a593Smuzhiyun const unsigned int phase[] = { 0, BATCH };
3610*4882a593Smuzhiyun struct igt_live_test t;
3611*4882a593Smuzhiyun int err = -ENOMEM;
3612*4882a593Smuzhiyun u32 *cs;
3613*4882a593Smuzhiyun int n;
3614*4882a593Smuzhiyun
3615*4882a593Smuzhiyun if (!HAS_LOGICAL_RING_PREEMPTION(smoke.gt->i915))
3616*4882a593Smuzhiyun return 0;
3617*4882a593Smuzhiyun
3618*4882a593Smuzhiyun smoke.contexts = kmalloc_array(smoke.ncontext,
3619*4882a593Smuzhiyun sizeof(*smoke.contexts),
3620*4882a593Smuzhiyun GFP_KERNEL);
3621*4882a593Smuzhiyun if (!smoke.contexts)
3622*4882a593Smuzhiyun return -ENOMEM;
3623*4882a593Smuzhiyun
3624*4882a593Smuzhiyun smoke.batch =
3625*4882a593Smuzhiyun i915_gem_object_create_internal(smoke.gt->i915, PAGE_SIZE);
3626*4882a593Smuzhiyun if (IS_ERR(smoke.batch)) {
3627*4882a593Smuzhiyun err = PTR_ERR(smoke.batch);
3628*4882a593Smuzhiyun goto err_free;
3629*4882a593Smuzhiyun }
3630*4882a593Smuzhiyun
3631*4882a593Smuzhiyun cs = i915_gem_object_pin_map(smoke.batch, I915_MAP_WB);
3632*4882a593Smuzhiyun if (IS_ERR(cs)) {
3633*4882a593Smuzhiyun err = PTR_ERR(cs);
3634*4882a593Smuzhiyun goto err_batch;
3635*4882a593Smuzhiyun }
3636*4882a593Smuzhiyun for (n = 0; n < PAGE_SIZE / sizeof(*cs) - 1; n++)
3637*4882a593Smuzhiyun cs[n] = MI_ARB_CHECK;
3638*4882a593Smuzhiyun cs[n] = MI_BATCH_BUFFER_END;
3639*4882a593Smuzhiyun i915_gem_object_flush_map(smoke.batch);
3640*4882a593Smuzhiyun i915_gem_object_unpin_map(smoke.batch);
3641*4882a593Smuzhiyun
3642*4882a593Smuzhiyun if (igt_live_test_begin(&t, smoke.gt->i915, __func__, "all")) {
3643*4882a593Smuzhiyun err = -EIO;
3644*4882a593Smuzhiyun goto err_batch;
3645*4882a593Smuzhiyun }
3646*4882a593Smuzhiyun
3647*4882a593Smuzhiyun for (n = 0; n < smoke.ncontext; n++) {
3648*4882a593Smuzhiyun smoke.contexts[n] = kernel_context(smoke.gt->i915);
3649*4882a593Smuzhiyun if (!smoke.contexts[n])
3650*4882a593Smuzhiyun goto err_ctx;
3651*4882a593Smuzhiyun }
3652*4882a593Smuzhiyun
3653*4882a593Smuzhiyun for (n = 0; n < ARRAY_SIZE(phase); n++) {
3654*4882a593Smuzhiyun err = smoke_crescendo(&smoke, phase[n]);
3655*4882a593Smuzhiyun if (err)
3656*4882a593Smuzhiyun goto err_ctx;
3657*4882a593Smuzhiyun
3658*4882a593Smuzhiyun err = smoke_random(&smoke, phase[n]);
3659*4882a593Smuzhiyun if (err)
3660*4882a593Smuzhiyun goto err_ctx;
3661*4882a593Smuzhiyun }
3662*4882a593Smuzhiyun
3663*4882a593Smuzhiyun err_ctx:
3664*4882a593Smuzhiyun if (igt_live_test_end(&t))
3665*4882a593Smuzhiyun err = -EIO;
3666*4882a593Smuzhiyun
3667*4882a593Smuzhiyun for (n = 0; n < smoke.ncontext; n++) {
3668*4882a593Smuzhiyun if (!smoke.contexts[n])
3669*4882a593Smuzhiyun break;
3670*4882a593Smuzhiyun kernel_context_close(smoke.contexts[n]);
3671*4882a593Smuzhiyun }
3672*4882a593Smuzhiyun
3673*4882a593Smuzhiyun err_batch:
3674*4882a593Smuzhiyun i915_gem_object_put(smoke.batch);
3675*4882a593Smuzhiyun err_free:
3676*4882a593Smuzhiyun kfree(smoke.contexts);
3677*4882a593Smuzhiyun
3678*4882a593Smuzhiyun return err;
3679*4882a593Smuzhiyun }
3680*4882a593Smuzhiyun
nop_virtual_engine(struct intel_gt * gt,struct intel_engine_cs ** siblings,unsigned int nsibling,unsigned int nctx,unsigned int flags)3681*4882a593Smuzhiyun static int nop_virtual_engine(struct intel_gt *gt,
3682*4882a593Smuzhiyun struct intel_engine_cs **siblings,
3683*4882a593Smuzhiyun unsigned int nsibling,
3684*4882a593Smuzhiyun unsigned int nctx,
3685*4882a593Smuzhiyun unsigned int flags)
3686*4882a593Smuzhiyun #define CHAIN BIT(0)
3687*4882a593Smuzhiyun {
3688*4882a593Smuzhiyun IGT_TIMEOUT(end_time);
3689*4882a593Smuzhiyun struct i915_request *request[16] = {};
3690*4882a593Smuzhiyun struct intel_context *ve[16];
3691*4882a593Smuzhiyun unsigned long n, prime, nc;
3692*4882a593Smuzhiyun struct igt_live_test t;
3693*4882a593Smuzhiyun ktime_t times[2] = {};
3694*4882a593Smuzhiyun int err;
3695*4882a593Smuzhiyun
3696*4882a593Smuzhiyun GEM_BUG_ON(!nctx || nctx > ARRAY_SIZE(ve));
3697*4882a593Smuzhiyun
3698*4882a593Smuzhiyun for (n = 0; n < nctx; n++) {
3699*4882a593Smuzhiyun ve[n] = intel_execlists_create_virtual(siblings, nsibling);
3700*4882a593Smuzhiyun if (IS_ERR(ve[n])) {
3701*4882a593Smuzhiyun err = PTR_ERR(ve[n]);
3702*4882a593Smuzhiyun nctx = n;
3703*4882a593Smuzhiyun goto out;
3704*4882a593Smuzhiyun }
3705*4882a593Smuzhiyun
3706*4882a593Smuzhiyun err = intel_context_pin(ve[n]);
3707*4882a593Smuzhiyun if (err) {
3708*4882a593Smuzhiyun intel_context_put(ve[n]);
3709*4882a593Smuzhiyun nctx = n;
3710*4882a593Smuzhiyun goto out;
3711*4882a593Smuzhiyun }
3712*4882a593Smuzhiyun }
3713*4882a593Smuzhiyun
3714*4882a593Smuzhiyun err = igt_live_test_begin(&t, gt->i915, __func__, ve[0]->engine->name);
3715*4882a593Smuzhiyun if (err)
3716*4882a593Smuzhiyun goto out;
3717*4882a593Smuzhiyun
3718*4882a593Smuzhiyun for_each_prime_number_from(prime, 1, 8192) {
3719*4882a593Smuzhiyun times[1] = ktime_get_raw();
3720*4882a593Smuzhiyun
3721*4882a593Smuzhiyun if (flags & CHAIN) {
3722*4882a593Smuzhiyun for (nc = 0; nc < nctx; nc++) {
3723*4882a593Smuzhiyun for (n = 0; n < prime; n++) {
3724*4882a593Smuzhiyun struct i915_request *rq;
3725*4882a593Smuzhiyun
3726*4882a593Smuzhiyun rq = i915_request_create(ve[nc]);
3727*4882a593Smuzhiyun if (IS_ERR(rq)) {
3728*4882a593Smuzhiyun err = PTR_ERR(rq);
3729*4882a593Smuzhiyun goto out;
3730*4882a593Smuzhiyun }
3731*4882a593Smuzhiyun
3732*4882a593Smuzhiyun if (request[nc])
3733*4882a593Smuzhiyun i915_request_put(request[nc]);
3734*4882a593Smuzhiyun request[nc] = i915_request_get(rq);
3735*4882a593Smuzhiyun i915_request_add(rq);
3736*4882a593Smuzhiyun }
3737*4882a593Smuzhiyun }
3738*4882a593Smuzhiyun } else {
3739*4882a593Smuzhiyun for (n = 0; n < prime; n++) {
3740*4882a593Smuzhiyun for (nc = 0; nc < nctx; nc++) {
3741*4882a593Smuzhiyun struct i915_request *rq;
3742*4882a593Smuzhiyun
3743*4882a593Smuzhiyun rq = i915_request_create(ve[nc]);
3744*4882a593Smuzhiyun if (IS_ERR(rq)) {
3745*4882a593Smuzhiyun err = PTR_ERR(rq);
3746*4882a593Smuzhiyun goto out;
3747*4882a593Smuzhiyun }
3748*4882a593Smuzhiyun
3749*4882a593Smuzhiyun if (request[nc])
3750*4882a593Smuzhiyun i915_request_put(request[nc]);
3751*4882a593Smuzhiyun request[nc] = i915_request_get(rq);
3752*4882a593Smuzhiyun i915_request_add(rq);
3753*4882a593Smuzhiyun }
3754*4882a593Smuzhiyun }
3755*4882a593Smuzhiyun }
3756*4882a593Smuzhiyun
3757*4882a593Smuzhiyun for (nc = 0; nc < nctx; nc++) {
3758*4882a593Smuzhiyun if (i915_request_wait(request[nc], 0, HZ / 10) < 0) {
3759*4882a593Smuzhiyun pr_err("%s(%s): wait for %llx:%lld timed out\n",
3760*4882a593Smuzhiyun __func__, ve[0]->engine->name,
3761*4882a593Smuzhiyun request[nc]->fence.context,
3762*4882a593Smuzhiyun request[nc]->fence.seqno);
3763*4882a593Smuzhiyun
3764*4882a593Smuzhiyun GEM_TRACE("%s(%s) failed at request %llx:%lld\n",
3765*4882a593Smuzhiyun __func__, ve[0]->engine->name,
3766*4882a593Smuzhiyun request[nc]->fence.context,
3767*4882a593Smuzhiyun request[nc]->fence.seqno);
3768*4882a593Smuzhiyun GEM_TRACE_DUMP();
3769*4882a593Smuzhiyun intel_gt_set_wedged(gt);
3770*4882a593Smuzhiyun break;
3771*4882a593Smuzhiyun }
3772*4882a593Smuzhiyun }
3773*4882a593Smuzhiyun
3774*4882a593Smuzhiyun times[1] = ktime_sub(ktime_get_raw(), times[1]);
3775*4882a593Smuzhiyun if (prime == 1)
3776*4882a593Smuzhiyun times[0] = times[1];
3777*4882a593Smuzhiyun
3778*4882a593Smuzhiyun for (nc = 0; nc < nctx; nc++) {
3779*4882a593Smuzhiyun i915_request_put(request[nc]);
3780*4882a593Smuzhiyun request[nc] = NULL;
3781*4882a593Smuzhiyun }
3782*4882a593Smuzhiyun
3783*4882a593Smuzhiyun if (__igt_timeout(end_time, NULL))
3784*4882a593Smuzhiyun break;
3785*4882a593Smuzhiyun }
3786*4882a593Smuzhiyun
3787*4882a593Smuzhiyun err = igt_live_test_end(&t);
3788*4882a593Smuzhiyun if (err)
3789*4882a593Smuzhiyun goto out;
3790*4882a593Smuzhiyun
3791*4882a593Smuzhiyun pr_info("Requestx%d latencies on %s: 1 = %lluns, %lu = %lluns\n",
3792*4882a593Smuzhiyun nctx, ve[0]->engine->name, ktime_to_ns(times[0]),
3793*4882a593Smuzhiyun prime, div64_u64(ktime_to_ns(times[1]), prime));
3794*4882a593Smuzhiyun
3795*4882a593Smuzhiyun out:
3796*4882a593Smuzhiyun if (igt_flush_test(gt->i915))
3797*4882a593Smuzhiyun err = -EIO;
3798*4882a593Smuzhiyun
3799*4882a593Smuzhiyun for (nc = 0; nc < nctx; nc++) {
3800*4882a593Smuzhiyun i915_request_put(request[nc]);
3801*4882a593Smuzhiyun intel_context_unpin(ve[nc]);
3802*4882a593Smuzhiyun intel_context_put(ve[nc]);
3803*4882a593Smuzhiyun }
3804*4882a593Smuzhiyun return err;
3805*4882a593Smuzhiyun }
3806*4882a593Smuzhiyun
3807*4882a593Smuzhiyun static unsigned int
__select_siblings(struct intel_gt * gt,unsigned int class,struct intel_engine_cs ** siblings,bool (* filter)(const struct intel_engine_cs *))3808*4882a593Smuzhiyun __select_siblings(struct intel_gt *gt,
3809*4882a593Smuzhiyun unsigned int class,
3810*4882a593Smuzhiyun struct intel_engine_cs **siblings,
3811*4882a593Smuzhiyun bool (*filter)(const struct intel_engine_cs *))
3812*4882a593Smuzhiyun {
3813*4882a593Smuzhiyun unsigned int n = 0;
3814*4882a593Smuzhiyun unsigned int inst;
3815*4882a593Smuzhiyun
3816*4882a593Smuzhiyun for (inst = 0; inst <= MAX_ENGINE_INSTANCE; inst++) {
3817*4882a593Smuzhiyun if (!gt->engine_class[class][inst])
3818*4882a593Smuzhiyun continue;
3819*4882a593Smuzhiyun
3820*4882a593Smuzhiyun if (filter && !filter(gt->engine_class[class][inst]))
3821*4882a593Smuzhiyun continue;
3822*4882a593Smuzhiyun
3823*4882a593Smuzhiyun siblings[n++] = gt->engine_class[class][inst];
3824*4882a593Smuzhiyun }
3825*4882a593Smuzhiyun
3826*4882a593Smuzhiyun return n;
3827*4882a593Smuzhiyun }
3828*4882a593Smuzhiyun
3829*4882a593Smuzhiyun static unsigned int
select_siblings(struct intel_gt * gt,unsigned int class,struct intel_engine_cs ** siblings)3830*4882a593Smuzhiyun select_siblings(struct intel_gt *gt,
3831*4882a593Smuzhiyun unsigned int class,
3832*4882a593Smuzhiyun struct intel_engine_cs **siblings)
3833*4882a593Smuzhiyun {
3834*4882a593Smuzhiyun return __select_siblings(gt, class, siblings, NULL);
3835*4882a593Smuzhiyun }
3836*4882a593Smuzhiyun
live_virtual_engine(void * arg)3837*4882a593Smuzhiyun static int live_virtual_engine(void *arg)
3838*4882a593Smuzhiyun {
3839*4882a593Smuzhiyun struct intel_gt *gt = arg;
3840*4882a593Smuzhiyun struct intel_engine_cs *siblings[MAX_ENGINE_INSTANCE + 1];
3841*4882a593Smuzhiyun struct intel_engine_cs *engine;
3842*4882a593Smuzhiyun enum intel_engine_id id;
3843*4882a593Smuzhiyun unsigned int class;
3844*4882a593Smuzhiyun int err;
3845*4882a593Smuzhiyun
3846*4882a593Smuzhiyun if (intel_uc_uses_guc_submission(>->uc))
3847*4882a593Smuzhiyun return 0;
3848*4882a593Smuzhiyun
3849*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
3850*4882a593Smuzhiyun err = nop_virtual_engine(gt, &engine, 1, 1, 0);
3851*4882a593Smuzhiyun if (err) {
3852*4882a593Smuzhiyun pr_err("Failed to wrap engine %s: err=%d\n",
3853*4882a593Smuzhiyun engine->name, err);
3854*4882a593Smuzhiyun return err;
3855*4882a593Smuzhiyun }
3856*4882a593Smuzhiyun }
3857*4882a593Smuzhiyun
3858*4882a593Smuzhiyun for (class = 0; class <= MAX_ENGINE_CLASS; class++) {
3859*4882a593Smuzhiyun int nsibling, n;
3860*4882a593Smuzhiyun
3861*4882a593Smuzhiyun nsibling = select_siblings(gt, class, siblings);
3862*4882a593Smuzhiyun if (nsibling < 2)
3863*4882a593Smuzhiyun continue;
3864*4882a593Smuzhiyun
3865*4882a593Smuzhiyun for (n = 1; n <= nsibling + 1; n++) {
3866*4882a593Smuzhiyun err = nop_virtual_engine(gt, siblings, nsibling,
3867*4882a593Smuzhiyun n, 0);
3868*4882a593Smuzhiyun if (err)
3869*4882a593Smuzhiyun return err;
3870*4882a593Smuzhiyun }
3871*4882a593Smuzhiyun
3872*4882a593Smuzhiyun err = nop_virtual_engine(gt, siblings, nsibling, n, CHAIN);
3873*4882a593Smuzhiyun if (err)
3874*4882a593Smuzhiyun return err;
3875*4882a593Smuzhiyun }
3876*4882a593Smuzhiyun
3877*4882a593Smuzhiyun return 0;
3878*4882a593Smuzhiyun }
3879*4882a593Smuzhiyun
mask_virtual_engine(struct intel_gt * gt,struct intel_engine_cs ** siblings,unsigned int nsibling)3880*4882a593Smuzhiyun static int mask_virtual_engine(struct intel_gt *gt,
3881*4882a593Smuzhiyun struct intel_engine_cs **siblings,
3882*4882a593Smuzhiyun unsigned int nsibling)
3883*4882a593Smuzhiyun {
3884*4882a593Smuzhiyun struct i915_request *request[MAX_ENGINE_INSTANCE + 1];
3885*4882a593Smuzhiyun struct intel_context *ve;
3886*4882a593Smuzhiyun struct igt_live_test t;
3887*4882a593Smuzhiyun unsigned int n;
3888*4882a593Smuzhiyun int err;
3889*4882a593Smuzhiyun
3890*4882a593Smuzhiyun /*
3891*4882a593Smuzhiyun * Check that by setting the execution mask on a request, we can
3892*4882a593Smuzhiyun * restrict it to our desired engine within the virtual engine.
3893*4882a593Smuzhiyun */
3894*4882a593Smuzhiyun
3895*4882a593Smuzhiyun ve = intel_execlists_create_virtual(siblings, nsibling);
3896*4882a593Smuzhiyun if (IS_ERR(ve)) {
3897*4882a593Smuzhiyun err = PTR_ERR(ve);
3898*4882a593Smuzhiyun goto out_close;
3899*4882a593Smuzhiyun }
3900*4882a593Smuzhiyun
3901*4882a593Smuzhiyun err = intel_context_pin(ve);
3902*4882a593Smuzhiyun if (err)
3903*4882a593Smuzhiyun goto out_put;
3904*4882a593Smuzhiyun
3905*4882a593Smuzhiyun err = igt_live_test_begin(&t, gt->i915, __func__, ve->engine->name);
3906*4882a593Smuzhiyun if (err)
3907*4882a593Smuzhiyun goto out_unpin;
3908*4882a593Smuzhiyun
3909*4882a593Smuzhiyun for (n = 0; n < nsibling; n++) {
3910*4882a593Smuzhiyun request[n] = i915_request_create(ve);
3911*4882a593Smuzhiyun if (IS_ERR(request[n])) {
3912*4882a593Smuzhiyun err = PTR_ERR(request[n]);
3913*4882a593Smuzhiyun nsibling = n;
3914*4882a593Smuzhiyun goto out;
3915*4882a593Smuzhiyun }
3916*4882a593Smuzhiyun
3917*4882a593Smuzhiyun /* Reverse order as it's more likely to be unnatural */
3918*4882a593Smuzhiyun request[n]->execution_mask = siblings[nsibling - n - 1]->mask;
3919*4882a593Smuzhiyun
3920*4882a593Smuzhiyun i915_request_get(request[n]);
3921*4882a593Smuzhiyun i915_request_add(request[n]);
3922*4882a593Smuzhiyun }
3923*4882a593Smuzhiyun
3924*4882a593Smuzhiyun for (n = 0; n < nsibling; n++) {
3925*4882a593Smuzhiyun if (i915_request_wait(request[n], 0, HZ / 10) < 0) {
3926*4882a593Smuzhiyun pr_err("%s(%s): wait for %llx:%lld timed out\n",
3927*4882a593Smuzhiyun __func__, ve->engine->name,
3928*4882a593Smuzhiyun request[n]->fence.context,
3929*4882a593Smuzhiyun request[n]->fence.seqno);
3930*4882a593Smuzhiyun
3931*4882a593Smuzhiyun GEM_TRACE("%s(%s) failed at request %llx:%lld\n",
3932*4882a593Smuzhiyun __func__, ve->engine->name,
3933*4882a593Smuzhiyun request[n]->fence.context,
3934*4882a593Smuzhiyun request[n]->fence.seqno);
3935*4882a593Smuzhiyun GEM_TRACE_DUMP();
3936*4882a593Smuzhiyun intel_gt_set_wedged(gt);
3937*4882a593Smuzhiyun err = -EIO;
3938*4882a593Smuzhiyun goto out;
3939*4882a593Smuzhiyun }
3940*4882a593Smuzhiyun
3941*4882a593Smuzhiyun if (request[n]->engine != siblings[nsibling - n - 1]) {
3942*4882a593Smuzhiyun pr_err("Executed on wrong sibling '%s', expected '%s'\n",
3943*4882a593Smuzhiyun request[n]->engine->name,
3944*4882a593Smuzhiyun siblings[nsibling - n - 1]->name);
3945*4882a593Smuzhiyun err = -EINVAL;
3946*4882a593Smuzhiyun goto out;
3947*4882a593Smuzhiyun }
3948*4882a593Smuzhiyun }
3949*4882a593Smuzhiyun
3950*4882a593Smuzhiyun err = igt_live_test_end(&t);
3951*4882a593Smuzhiyun out:
3952*4882a593Smuzhiyun if (igt_flush_test(gt->i915))
3953*4882a593Smuzhiyun err = -EIO;
3954*4882a593Smuzhiyun
3955*4882a593Smuzhiyun for (n = 0; n < nsibling; n++)
3956*4882a593Smuzhiyun i915_request_put(request[n]);
3957*4882a593Smuzhiyun
3958*4882a593Smuzhiyun out_unpin:
3959*4882a593Smuzhiyun intel_context_unpin(ve);
3960*4882a593Smuzhiyun out_put:
3961*4882a593Smuzhiyun intel_context_put(ve);
3962*4882a593Smuzhiyun out_close:
3963*4882a593Smuzhiyun return err;
3964*4882a593Smuzhiyun }
3965*4882a593Smuzhiyun
live_virtual_mask(void * arg)3966*4882a593Smuzhiyun static int live_virtual_mask(void *arg)
3967*4882a593Smuzhiyun {
3968*4882a593Smuzhiyun struct intel_gt *gt = arg;
3969*4882a593Smuzhiyun struct intel_engine_cs *siblings[MAX_ENGINE_INSTANCE + 1];
3970*4882a593Smuzhiyun unsigned int class;
3971*4882a593Smuzhiyun int err;
3972*4882a593Smuzhiyun
3973*4882a593Smuzhiyun if (intel_uc_uses_guc_submission(>->uc))
3974*4882a593Smuzhiyun return 0;
3975*4882a593Smuzhiyun
3976*4882a593Smuzhiyun for (class = 0; class <= MAX_ENGINE_CLASS; class++) {
3977*4882a593Smuzhiyun unsigned int nsibling;
3978*4882a593Smuzhiyun
3979*4882a593Smuzhiyun nsibling = select_siblings(gt, class, siblings);
3980*4882a593Smuzhiyun if (nsibling < 2)
3981*4882a593Smuzhiyun continue;
3982*4882a593Smuzhiyun
3983*4882a593Smuzhiyun err = mask_virtual_engine(gt, siblings, nsibling);
3984*4882a593Smuzhiyun if (err)
3985*4882a593Smuzhiyun return err;
3986*4882a593Smuzhiyun }
3987*4882a593Smuzhiyun
3988*4882a593Smuzhiyun return 0;
3989*4882a593Smuzhiyun }
3990*4882a593Smuzhiyun
slicein_virtual_engine(struct intel_gt * gt,struct intel_engine_cs ** siblings,unsigned int nsibling)3991*4882a593Smuzhiyun static int slicein_virtual_engine(struct intel_gt *gt,
3992*4882a593Smuzhiyun struct intel_engine_cs **siblings,
3993*4882a593Smuzhiyun unsigned int nsibling)
3994*4882a593Smuzhiyun {
3995*4882a593Smuzhiyun const long timeout = slice_timeout(siblings[0]);
3996*4882a593Smuzhiyun struct intel_context *ce;
3997*4882a593Smuzhiyun struct i915_request *rq;
3998*4882a593Smuzhiyun struct igt_spinner spin;
3999*4882a593Smuzhiyun unsigned int n;
4000*4882a593Smuzhiyun int err = 0;
4001*4882a593Smuzhiyun
4002*4882a593Smuzhiyun /*
4003*4882a593Smuzhiyun * Virtual requests must take part in timeslicing on the target engines.
4004*4882a593Smuzhiyun */
4005*4882a593Smuzhiyun
4006*4882a593Smuzhiyun if (igt_spinner_init(&spin, gt))
4007*4882a593Smuzhiyun return -ENOMEM;
4008*4882a593Smuzhiyun
4009*4882a593Smuzhiyun for (n = 0; n < nsibling; n++) {
4010*4882a593Smuzhiyun ce = intel_context_create(siblings[n]);
4011*4882a593Smuzhiyun if (IS_ERR(ce)) {
4012*4882a593Smuzhiyun err = PTR_ERR(ce);
4013*4882a593Smuzhiyun goto out;
4014*4882a593Smuzhiyun }
4015*4882a593Smuzhiyun
4016*4882a593Smuzhiyun rq = igt_spinner_create_request(&spin, ce, MI_ARB_CHECK);
4017*4882a593Smuzhiyun intel_context_put(ce);
4018*4882a593Smuzhiyun if (IS_ERR(rq)) {
4019*4882a593Smuzhiyun err = PTR_ERR(rq);
4020*4882a593Smuzhiyun goto out;
4021*4882a593Smuzhiyun }
4022*4882a593Smuzhiyun
4023*4882a593Smuzhiyun i915_request_add(rq);
4024*4882a593Smuzhiyun }
4025*4882a593Smuzhiyun
4026*4882a593Smuzhiyun ce = intel_execlists_create_virtual(siblings, nsibling);
4027*4882a593Smuzhiyun if (IS_ERR(ce)) {
4028*4882a593Smuzhiyun err = PTR_ERR(ce);
4029*4882a593Smuzhiyun goto out;
4030*4882a593Smuzhiyun }
4031*4882a593Smuzhiyun
4032*4882a593Smuzhiyun rq = intel_context_create_request(ce);
4033*4882a593Smuzhiyun intel_context_put(ce);
4034*4882a593Smuzhiyun if (IS_ERR(rq)) {
4035*4882a593Smuzhiyun err = PTR_ERR(rq);
4036*4882a593Smuzhiyun goto out;
4037*4882a593Smuzhiyun }
4038*4882a593Smuzhiyun
4039*4882a593Smuzhiyun i915_request_get(rq);
4040*4882a593Smuzhiyun i915_request_add(rq);
4041*4882a593Smuzhiyun if (i915_request_wait(rq, 0, timeout) < 0) {
4042*4882a593Smuzhiyun GEM_TRACE_ERR("%s(%s) failed to slice in virtual request\n",
4043*4882a593Smuzhiyun __func__, rq->engine->name);
4044*4882a593Smuzhiyun GEM_TRACE_DUMP();
4045*4882a593Smuzhiyun intel_gt_set_wedged(gt);
4046*4882a593Smuzhiyun err = -EIO;
4047*4882a593Smuzhiyun }
4048*4882a593Smuzhiyun i915_request_put(rq);
4049*4882a593Smuzhiyun
4050*4882a593Smuzhiyun out:
4051*4882a593Smuzhiyun igt_spinner_end(&spin);
4052*4882a593Smuzhiyun if (igt_flush_test(gt->i915))
4053*4882a593Smuzhiyun err = -EIO;
4054*4882a593Smuzhiyun igt_spinner_fini(&spin);
4055*4882a593Smuzhiyun return err;
4056*4882a593Smuzhiyun }
4057*4882a593Smuzhiyun
sliceout_virtual_engine(struct intel_gt * gt,struct intel_engine_cs ** siblings,unsigned int nsibling)4058*4882a593Smuzhiyun static int sliceout_virtual_engine(struct intel_gt *gt,
4059*4882a593Smuzhiyun struct intel_engine_cs **siblings,
4060*4882a593Smuzhiyun unsigned int nsibling)
4061*4882a593Smuzhiyun {
4062*4882a593Smuzhiyun const long timeout = slice_timeout(siblings[0]);
4063*4882a593Smuzhiyun struct intel_context *ce;
4064*4882a593Smuzhiyun struct i915_request *rq;
4065*4882a593Smuzhiyun struct igt_spinner spin;
4066*4882a593Smuzhiyun unsigned int n;
4067*4882a593Smuzhiyun int err = 0;
4068*4882a593Smuzhiyun
4069*4882a593Smuzhiyun /*
4070*4882a593Smuzhiyun * Virtual requests must allow others a fair timeslice.
4071*4882a593Smuzhiyun */
4072*4882a593Smuzhiyun
4073*4882a593Smuzhiyun if (igt_spinner_init(&spin, gt))
4074*4882a593Smuzhiyun return -ENOMEM;
4075*4882a593Smuzhiyun
4076*4882a593Smuzhiyun /* XXX We do not handle oversubscription and fairness with normal rq */
4077*4882a593Smuzhiyun for (n = 0; n < nsibling; n++) {
4078*4882a593Smuzhiyun ce = intel_execlists_create_virtual(siblings, nsibling);
4079*4882a593Smuzhiyun if (IS_ERR(ce)) {
4080*4882a593Smuzhiyun err = PTR_ERR(ce);
4081*4882a593Smuzhiyun goto out;
4082*4882a593Smuzhiyun }
4083*4882a593Smuzhiyun
4084*4882a593Smuzhiyun rq = igt_spinner_create_request(&spin, ce, MI_ARB_CHECK);
4085*4882a593Smuzhiyun intel_context_put(ce);
4086*4882a593Smuzhiyun if (IS_ERR(rq)) {
4087*4882a593Smuzhiyun err = PTR_ERR(rq);
4088*4882a593Smuzhiyun goto out;
4089*4882a593Smuzhiyun }
4090*4882a593Smuzhiyun
4091*4882a593Smuzhiyun i915_request_add(rq);
4092*4882a593Smuzhiyun }
4093*4882a593Smuzhiyun
4094*4882a593Smuzhiyun for (n = 0; !err && n < nsibling; n++) {
4095*4882a593Smuzhiyun ce = intel_context_create(siblings[n]);
4096*4882a593Smuzhiyun if (IS_ERR(ce)) {
4097*4882a593Smuzhiyun err = PTR_ERR(ce);
4098*4882a593Smuzhiyun goto out;
4099*4882a593Smuzhiyun }
4100*4882a593Smuzhiyun
4101*4882a593Smuzhiyun rq = intel_context_create_request(ce);
4102*4882a593Smuzhiyun intel_context_put(ce);
4103*4882a593Smuzhiyun if (IS_ERR(rq)) {
4104*4882a593Smuzhiyun err = PTR_ERR(rq);
4105*4882a593Smuzhiyun goto out;
4106*4882a593Smuzhiyun }
4107*4882a593Smuzhiyun
4108*4882a593Smuzhiyun i915_request_get(rq);
4109*4882a593Smuzhiyun i915_request_add(rq);
4110*4882a593Smuzhiyun if (i915_request_wait(rq, 0, timeout) < 0) {
4111*4882a593Smuzhiyun GEM_TRACE_ERR("%s(%s) failed to slice out virtual request\n",
4112*4882a593Smuzhiyun __func__, siblings[n]->name);
4113*4882a593Smuzhiyun GEM_TRACE_DUMP();
4114*4882a593Smuzhiyun intel_gt_set_wedged(gt);
4115*4882a593Smuzhiyun err = -EIO;
4116*4882a593Smuzhiyun }
4117*4882a593Smuzhiyun i915_request_put(rq);
4118*4882a593Smuzhiyun }
4119*4882a593Smuzhiyun
4120*4882a593Smuzhiyun out:
4121*4882a593Smuzhiyun igt_spinner_end(&spin);
4122*4882a593Smuzhiyun if (igt_flush_test(gt->i915))
4123*4882a593Smuzhiyun err = -EIO;
4124*4882a593Smuzhiyun igt_spinner_fini(&spin);
4125*4882a593Smuzhiyun return err;
4126*4882a593Smuzhiyun }
4127*4882a593Smuzhiyun
live_virtual_slice(void * arg)4128*4882a593Smuzhiyun static int live_virtual_slice(void *arg)
4129*4882a593Smuzhiyun {
4130*4882a593Smuzhiyun struct intel_gt *gt = arg;
4131*4882a593Smuzhiyun struct intel_engine_cs *siblings[MAX_ENGINE_INSTANCE + 1];
4132*4882a593Smuzhiyun unsigned int class;
4133*4882a593Smuzhiyun int err;
4134*4882a593Smuzhiyun
4135*4882a593Smuzhiyun if (intel_uc_uses_guc_submission(>->uc))
4136*4882a593Smuzhiyun return 0;
4137*4882a593Smuzhiyun
4138*4882a593Smuzhiyun for (class = 0; class <= MAX_ENGINE_CLASS; class++) {
4139*4882a593Smuzhiyun unsigned int nsibling;
4140*4882a593Smuzhiyun
4141*4882a593Smuzhiyun nsibling = __select_siblings(gt, class, siblings,
4142*4882a593Smuzhiyun intel_engine_has_timeslices);
4143*4882a593Smuzhiyun if (nsibling < 2)
4144*4882a593Smuzhiyun continue;
4145*4882a593Smuzhiyun
4146*4882a593Smuzhiyun err = slicein_virtual_engine(gt, siblings, nsibling);
4147*4882a593Smuzhiyun if (err)
4148*4882a593Smuzhiyun return err;
4149*4882a593Smuzhiyun
4150*4882a593Smuzhiyun err = sliceout_virtual_engine(gt, siblings, nsibling);
4151*4882a593Smuzhiyun if (err)
4152*4882a593Smuzhiyun return err;
4153*4882a593Smuzhiyun }
4154*4882a593Smuzhiyun
4155*4882a593Smuzhiyun return 0;
4156*4882a593Smuzhiyun }
4157*4882a593Smuzhiyun
preserved_virtual_engine(struct intel_gt * gt,struct intel_engine_cs ** siblings,unsigned int nsibling)4158*4882a593Smuzhiyun static int preserved_virtual_engine(struct intel_gt *gt,
4159*4882a593Smuzhiyun struct intel_engine_cs **siblings,
4160*4882a593Smuzhiyun unsigned int nsibling)
4161*4882a593Smuzhiyun {
4162*4882a593Smuzhiyun struct i915_request *last = NULL;
4163*4882a593Smuzhiyun struct intel_context *ve;
4164*4882a593Smuzhiyun struct i915_vma *scratch;
4165*4882a593Smuzhiyun struct igt_live_test t;
4166*4882a593Smuzhiyun unsigned int n;
4167*4882a593Smuzhiyun int err = 0;
4168*4882a593Smuzhiyun u32 *cs;
4169*4882a593Smuzhiyun
4170*4882a593Smuzhiyun scratch = create_scratch(siblings[0]->gt);
4171*4882a593Smuzhiyun if (IS_ERR(scratch))
4172*4882a593Smuzhiyun return PTR_ERR(scratch);
4173*4882a593Smuzhiyun
4174*4882a593Smuzhiyun err = i915_vma_sync(scratch);
4175*4882a593Smuzhiyun if (err)
4176*4882a593Smuzhiyun goto out_scratch;
4177*4882a593Smuzhiyun
4178*4882a593Smuzhiyun ve = intel_execlists_create_virtual(siblings, nsibling);
4179*4882a593Smuzhiyun if (IS_ERR(ve)) {
4180*4882a593Smuzhiyun err = PTR_ERR(ve);
4181*4882a593Smuzhiyun goto out_scratch;
4182*4882a593Smuzhiyun }
4183*4882a593Smuzhiyun
4184*4882a593Smuzhiyun err = intel_context_pin(ve);
4185*4882a593Smuzhiyun if (err)
4186*4882a593Smuzhiyun goto out_put;
4187*4882a593Smuzhiyun
4188*4882a593Smuzhiyun err = igt_live_test_begin(&t, gt->i915, __func__, ve->engine->name);
4189*4882a593Smuzhiyun if (err)
4190*4882a593Smuzhiyun goto out_unpin;
4191*4882a593Smuzhiyun
4192*4882a593Smuzhiyun for (n = 0; n < NUM_GPR_DW; n++) {
4193*4882a593Smuzhiyun struct intel_engine_cs *engine = siblings[n % nsibling];
4194*4882a593Smuzhiyun struct i915_request *rq;
4195*4882a593Smuzhiyun
4196*4882a593Smuzhiyun rq = i915_request_create(ve);
4197*4882a593Smuzhiyun if (IS_ERR(rq)) {
4198*4882a593Smuzhiyun err = PTR_ERR(rq);
4199*4882a593Smuzhiyun goto out_end;
4200*4882a593Smuzhiyun }
4201*4882a593Smuzhiyun
4202*4882a593Smuzhiyun i915_request_put(last);
4203*4882a593Smuzhiyun last = i915_request_get(rq);
4204*4882a593Smuzhiyun
4205*4882a593Smuzhiyun cs = intel_ring_begin(rq, 8);
4206*4882a593Smuzhiyun if (IS_ERR(cs)) {
4207*4882a593Smuzhiyun i915_request_add(rq);
4208*4882a593Smuzhiyun err = PTR_ERR(cs);
4209*4882a593Smuzhiyun goto out_end;
4210*4882a593Smuzhiyun }
4211*4882a593Smuzhiyun
4212*4882a593Smuzhiyun *cs++ = MI_STORE_REGISTER_MEM_GEN8 | MI_USE_GGTT;
4213*4882a593Smuzhiyun *cs++ = CS_GPR(engine, n);
4214*4882a593Smuzhiyun *cs++ = i915_ggtt_offset(scratch) + n * sizeof(u32);
4215*4882a593Smuzhiyun *cs++ = 0;
4216*4882a593Smuzhiyun
4217*4882a593Smuzhiyun *cs++ = MI_LOAD_REGISTER_IMM(1);
4218*4882a593Smuzhiyun *cs++ = CS_GPR(engine, (n + 1) % NUM_GPR_DW);
4219*4882a593Smuzhiyun *cs++ = n + 1;
4220*4882a593Smuzhiyun
4221*4882a593Smuzhiyun *cs++ = MI_NOOP;
4222*4882a593Smuzhiyun intel_ring_advance(rq, cs);
4223*4882a593Smuzhiyun
4224*4882a593Smuzhiyun /* Restrict this request to run on a particular engine */
4225*4882a593Smuzhiyun rq->execution_mask = engine->mask;
4226*4882a593Smuzhiyun i915_request_add(rq);
4227*4882a593Smuzhiyun }
4228*4882a593Smuzhiyun
4229*4882a593Smuzhiyun if (i915_request_wait(last, 0, HZ / 5) < 0) {
4230*4882a593Smuzhiyun err = -ETIME;
4231*4882a593Smuzhiyun goto out_end;
4232*4882a593Smuzhiyun }
4233*4882a593Smuzhiyun
4234*4882a593Smuzhiyun cs = i915_gem_object_pin_map(scratch->obj, I915_MAP_WB);
4235*4882a593Smuzhiyun if (IS_ERR(cs)) {
4236*4882a593Smuzhiyun err = PTR_ERR(cs);
4237*4882a593Smuzhiyun goto out_end;
4238*4882a593Smuzhiyun }
4239*4882a593Smuzhiyun
4240*4882a593Smuzhiyun for (n = 0; n < NUM_GPR_DW; n++) {
4241*4882a593Smuzhiyun if (cs[n] != n) {
4242*4882a593Smuzhiyun pr_err("Incorrect value[%d] found for GPR[%d]\n",
4243*4882a593Smuzhiyun cs[n], n);
4244*4882a593Smuzhiyun err = -EINVAL;
4245*4882a593Smuzhiyun break;
4246*4882a593Smuzhiyun }
4247*4882a593Smuzhiyun }
4248*4882a593Smuzhiyun
4249*4882a593Smuzhiyun i915_gem_object_unpin_map(scratch->obj);
4250*4882a593Smuzhiyun
4251*4882a593Smuzhiyun out_end:
4252*4882a593Smuzhiyun if (igt_live_test_end(&t))
4253*4882a593Smuzhiyun err = -EIO;
4254*4882a593Smuzhiyun i915_request_put(last);
4255*4882a593Smuzhiyun out_unpin:
4256*4882a593Smuzhiyun intel_context_unpin(ve);
4257*4882a593Smuzhiyun out_put:
4258*4882a593Smuzhiyun intel_context_put(ve);
4259*4882a593Smuzhiyun out_scratch:
4260*4882a593Smuzhiyun i915_vma_unpin_and_release(&scratch, 0);
4261*4882a593Smuzhiyun return err;
4262*4882a593Smuzhiyun }
4263*4882a593Smuzhiyun
live_virtual_preserved(void * arg)4264*4882a593Smuzhiyun static int live_virtual_preserved(void *arg)
4265*4882a593Smuzhiyun {
4266*4882a593Smuzhiyun struct intel_gt *gt = arg;
4267*4882a593Smuzhiyun struct intel_engine_cs *siblings[MAX_ENGINE_INSTANCE + 1];
4268*4882a593Smuzhiyun unsigned int class;
4269*4882a593Smuzhiyun
4270*4882a593Smuzhiyun /*
4271*4882a593Smuzhiyun * Check that the context image retains non-privileged (user) registers
4272*4882a593Smuzhiyun * from one engine to the next. For this we check that the CS_GPR
4273*4882a593Smuzhiyun * are preserved.
4274*4882a593Smuzhiyun */
4275*4882a593Smuzhiyun
4276*4882a593Smuzhiyun if (intel_uc_uses_guc_submission(>->uc))
4277*4882a593Smuzhiyun return 0;
4278*4882a593Smuzhiyun
4279*4882a593Smuzhiyun /* As we use CS_GPR we cannot run before they existed on all engines. */
4280*4882a593Smuzhiyun if (INTEL_GEN(gt->i915) < 9)
4281*4882a593Smuzhiyun return 0;
4282*4882a593Smuzhiyun
4283*4882a593Smuzhiyun for (class = 0; class <= MAX_ENGINE_CLASS; class++) {
4284*4882a593Smuzhiyun int nsibling, err;
4285*4882a593Smuzhiyun
4286*4882a593Smuzhiyun nsibling = select_siblings(gt, class, siblings);
4287*4882a593Smuzhiyun if (nsibling < 2)
4288*4882a593Smuzhiyun continue;
4289*4882a593Smuzhiyun
4290*4882a593Smuzhiyun err = preserved_virtual_engine(gt, siblings, nsibling);
4291*4882a593Smuzhiyun if (err)
4292*4882a593Smuzhiyun return err;
4293*4882a593Smuzhiyun }
4294*4882a593Smuzhiyun
4295*4882a593Smuzhiyun return 0;
4296*4882a593Smuzhiyun }
4297*4882a593Smuzhiyun
bond_virtual_engine(struct intel_gt * gt,unsigned int class,struct intel_engine_cs ** siblings,unsigned int nsibling,unsigned int flags)4298*4882a593Smuzhiyun static int bond_virtual_engine(struct intel_gt *gt,
4299*4882a593Smuzhiyun unsigned int class,
4300*4882a593Smuzhiyun struct intel_engine_cs **siblings,
4301*4882a593Smuzhiyun unsigned int nsibling,
4302*4882a593Smuzhiyun unsigned int flags)
4303*4882a593Smuzhiyun #define BOND_SCHEDULE BIT(0)
4304*4882a593Smuzhiyun {
4305*4882a593Smuzhiyun struct intel_engine_cs *master;
4306*4882a593Smuzhiyun struct i915_request *rq[16];
4307*4882a593Smuzhiyun enum intel_engine_id id;
4308*4882a593Smuzhiyun struct igt_spinner spin;
4309*4882a593Smuzhiyun unsigned long n;
4310*4882a593Smuzhiyun int err;
4311*4882a593Smuzhiyun
4312*4882a593Smuzhiyun /*
4313*4882a593Smuzhiyun * A set of bonded requests is intended to be run concurrently
4314*4882a593Smuzhiyun * across a number of engines. We use one request per-engine
4315*4882a593Smuzhiyun * and a magic fence to schedule each of the bonded requests
4316*4882a593Smuzhiyun * at the same time. A consequence of our current scheduler is that
4317*4882a593Smuzhiyun * we only move requests to the HW ready queue when the request
4318*4882a593Smuzhiyun * becomes ready, that is when all of its prerequisite fences have
4319*4882a593Smuzhiyun * been signaled. As one of those fences is the master submit fence,
4320*4882a593Smuzhiyun * there is a delay on all secondary fences as the HW may be
4321*4882a593Smuzhiyun * currently busy. Equally, as all the requests are independent,
4322*4882a593Smuzhiyun * they may have other fences that delay individual request
4323*4882a593Smuzhiyun * submission to HW. Ergo, we do not guarantee that all requests are
4324*4882a593Smuzhiyun * immediately submitted to HW at the same time, just that if the
4325*4882a593Smuzhiyun * rules are abided by, they are ready at the same time as the
4326*4882a593Smuzhiyun * first is submitted. Userspace can embed semaphores in its batch
4327*4882a593Smuzhiyun * to ensure parallel execution of its phases as it requires.
4328*4882a593Smuzhiyun * Though naturally it gets requested that perhaps the scheduler should
4329*4882a593Smuzhiyun * take care of parallel execution, even across preemption events on
4330*4882a593Smuzhiyun * different HW. (The proper answer is of course "lalalala".)
4331*4882a593Smuzhiyun *
4332*4882a593Smuzhiyun * With the submit-fence, we have identified three possible phases
4333*4882a593Smuzhiyun * of synchronisation depending on the master fence: queued (not
4334*4882a593Smuzhiyun * ready), executing, and signaled. The first two are quite simple
4335*4882a593Smuzhiyun * and checked below. However, the signaled master fence handling is
4336*4882a593Smuzhiyun * contentious. Currently we do not distinguish between a signaled
4337*4882a593Smuzhiyun * fence and an expired fence, as once signaled it does not convey
4338*4882a593Smuzhiyun * any information about the previous execution. It may even be freed
4339*4882a593Smuzhiyun * and hence checking later it may not exist at all. Ergo we currently
4340*4882a593Smuzhiyun * do not apply the bonding constraint for an already signaled fence,
4341*4882a593Smuzhiyun * as our expectation is that it should not constrain the secondaries
4342*4882a593Smuzhiyun * and is outside of the scope of the bonded request API (i.e. all
4343*4882a593Smuzhiyun * userspace requests are meant to be running in parallel). As
4344*4882a593Smuzhiyun * it imposes no constraint, and is effectively a no-op, we do not
4345*4882a593Smuzhiyun * check below as normal execution flows are checked extensively above.
4346*4882a593Smuzhiyun *
4347*4882a593Smuzhiyun * XXX Is the degenerate handling of signaled submit fences the
4348*4882a593Smuzhiyun * expected behaviour for userpace?
4349*4882a593Smuzhiyun */
4350*4882a593Smuzhiyun
4351*4882a593Smuzhiyun GEM_BUG_ON(nsibling >= ARRAY_SIZE(rq) - 1);
4352*4882a593Smuzhiyun
4353*4882a593Smuzhiyun if (igt_spinner_init(&spin, gt))
4354*4882a593Smuzhiyun return -ENOMEM;
4355*4882a593Smuzhiyun
4356*4882a593Smuzhiyun err = 0;
4357*4882a593Smuzhiyun rq[0] = ERR_PTR(-ENOMEM);
4358*4882a593Smuzhiyun for_each_engine(master, gt, id) {
4359*4882a593Smuzhiyun struct i915_sw_fence fence = {};
4360*4882a593Smuzhiyun struct intel_context *ce;
4361*4882a593Smuzhiyun
4362*4882a593Smuzhiyun if (master->class == class)
4363*4882a593Smuzhiyun continue;
4364*4882a593Smuzhiyun
4365*4882a593Smuzhiyun ce = intel_context_create(master);
4366*4882a593Smuzhiyun if (IS_ERR(ce)) {
4367*4882a593Smuzhiyun err = PTR_ERR(ce);
4368*4882a593Smuzhiyun goto out;
4369*4882a593Smuzhiyun }
4370*4882a593Smuzhiyun
4371*4882a593Smuzhiyun memset_p((void *)rq, ERR_PTR(-EINVAL), ARRAY_SIZE(rq));
4372*4882a593Smuzhiyun
4373*4882a593Smuzhiyun rq[0] = igt_spinner_create_request(&spin, ce, MI_NOOP);
4374*4882a593Smuzhiyun intel_context_put(ce);
4375*4882a593Smuzhiyun if (IS_ERR(rq[0])) {
4376*4882a593Smuzhiyun err = PTR_ERR(rq[0]);
4377*4882a593Smuzhiyun goto out;
4378*4882a593Smuzhiyun }
4379*4882a593Smuzhiyun i915_request_get(rq[0]);
4380*4882a593Smuzhiyun
4381*4882a593Smuzhiyun if (flags & BOND_SCHEDULE) {
4382*4882a593Smuzhiyun onstack_fence_init(&fence);
4383*4882a593Smuzhiyun err = i915_sw_fence_await_sw_fence_gfp(&rq[0]->submit,
4384*4882a593Smuzhiyun &fence,
4385*4882a593Smuzhiyun GFP_KERNEL);
4386*4882a593Smuzhiyun }
4387*4882a593Smuzhiyun
4388*4882a593Smuzhiyun i915_request_add(rq[0]);
4389*4882a593Smuzhiyun if (err < 0)
4390*4882a593Smuzhiyun goto out;
4391*4882a593Smuzhiyun
4392*4882a593Smuzhiyun if (!(flags & BOND_SCHEDULE) &&
4393*4882a593Smuzhiyun !igt_wait_for_spinner(&spin, rq[0])) {
4394*4882a593Smuzhiyun err = -EIO;
4395*4882a593Smuzhiyun goto out;
4396*4882a593Smuzhiyun }
4397*4882a593Smuzhiyun
4398*4882a593Smuzhiyun for (n = 0; n < nsibling; n++) {
4399*4882a593Smuzhiyun struct intel_context *ve;
4400*4882a593Smuzhiyun
4401*4882a593Smuzhiyun ve = intel_execlists_create_virtual(siblings, nsibling);
4402*4882a593Smuzhiyun if (IS_ERR(ve)) {
4403*4882a593Smuzhiyun err = PTR_ERR(ve);
4404*4882a593Smuzhiyun onstack_fence_fini(&fence);
4405*4882a593Smuzhiyun goto out;
4406*4882a593Smuzhiyun }
4407*4882a593Smuzhiyun
4408*4882a593Smuzhiyun err = intel_virtual_engine_attach_bond(ve->engine,
4409*4882a593Smuzhiyun master,
4410*4882a593Smuzhiyun siblings[n]);
4411*4882a593Smuzhiyun if (err) {
4412*4882a593Smuzhiyun intel_context_put(ve);
4413*4882a593Smuzhiyun onstack_fence_fini(&fence);
4414*4882a593Smuzhiyun goto out;
4415*4882a593Smuzhiyun }
4416*4882a593Smuzhiyun
4417*4882a593Smuzhiyun err = intel_context_pin(ve);
4418*4882a593Smuzhiyun intel_context_put(ve);
4419*4882a593Smuzhiyun if (err) {
4420*4882a593Smuzhiyun onstack_fence_fini(&fence);
4421*4882a593Smuzhiyun goto out;
4422*4882a593Smuzhiyun }
4423*4882a593Smuzhiyun
4424*4882a593Smuzhiyun rq[n + 1] = i915_request_create(ve);
4425*4882a593Smuzhiyun intel_context_unpin(ve);
4426*4882a593Smuzhiyun if (IS_ERR(rq[n + 1])) {
4427*4882a593Smuzhiyun err = PTR_ERR(rq[n + 1]);
4428*4882a593Smuzhiyun onstack_fence_fini(&fence);
4429*4882a593Smuzhiyun goto out;
4430*4882a593Smuzhiyun }
4431*4882a593Smuzhiyun i915_request_get(rq[n + 1]);
4432*4882a593Smuzhiyun
4433*4882a593Smuzhiyun err = i915_request_await_execution(rq[n + 1],
4434*4882a593Smuzhiyun &rq[0]->fence,
4435*4882a593Smuzhiyun ve->engine->bond_execute);
4436*4882a593Smuzhiyun i915_request_add(rq[n + 1]);
4437*4882a593Smuzhiyun if (err < 0) {
4438*4882a593Smuzhiyun onstack_fence_fini(&fence);
4439*4882a593Smuzhiyun goto out;
4440*4882a593Smuzhiyun }
4441*4882a593Smuzhiyun }
4442*4882a593Smuzhiyun onstack_fence_fini(&fence);
4443*4882a593Smuzhiyun intel_engine_flush_submission(master);
4444*4882a593Smuzhiyun igt_spinner_end(&spin);
4445*4882a593Smuzhiyun
4446*4882a593Smuzhiyun if (i915_request_wait(rq[0], 0, HZ / 10) < 0) {
4447*4882a593Smuzhiyun pr_err("Master request did not execute (on %s)!\n",
4448*4882a593Smuzhiyun rq[0]->engine->name);
4449*4882a593Smuzhiyun err = -EIO;
4450*4882a593Smuzhiyun goto out;
4451*4882a593Smuzhiyun }
4452*4882a593Smuzhiyun
4453*4882a593Smuzhiyun for (n = 0; n < nsibling; n++) {
4454*4882a593Smuzhiyun if (i915_request_wait(rq[n + 1], 0,
4455*4882a593Smuzhiyun MAX_SCHEDULE_TIMEOUT) < 0) {
4456*4882a593Smuzhiyun err = -EIO;
4457*4882a593Smuzhiyun goto out;
4458*4882a593Smuzhiyun }
4459*4882a593Smuzhiyun
4460*4882a593Smuzhiyun if (rq[n + 1]->engine != siblings[n]) {
4461*4882a593Smuzhiyun pr_err("Bonded request did not execute on target engine: expected %s, used %s; master was %s\n",
4462*4882a593Smuzhiyun siblings[n]->name,
4463*4882a593Smuzhiyun rq[n + 1]->engine->name,
4464*4882a593Smuzhiyun rq[0]->engine->name);
4465*4882a593Smuzhiyun err = -EINVAL;
4466*4882a593Smuzhiyun goto out;
4467*4882a593Smuzhiyun }
4468*4882a593Smuzhiyun }
4469*4882a593Smuzhiyun
4470*4882a593Smuzhiyun for (n = 0; !IS_ERR(rq[n]); n++)
4471*4882a593Smuzhiyun i915_request_put(rq[n]);
4472*4882a593Smuzhiyun rq[0] = ERR_PTR(-ENOMEM);
4473*4882a593Smuzhiyun }
4474*4882a593Smuzhiyun
4475*4882a593Smuzhiyun out:
4476*4882a593Smuzhiyun for (n = 0; !IS_ERR(rq[n]); n++)
4477*4882a593Smuzhiyun i915_request_put(rq[n]);
4478*4882a593Smuzhiyun if (igt_flush_test(gt->i915))
4479*4882a593Smuzhiyun err = -EIO;
4480*4882a593Smuzhiyun
4481*4882a593Smuzhiyun igt_spinner_fini(&spin);
4482*4882a593Smuzhiyun return err;
4483*4882a593Smuzhiyun }
4484*4882a593Smuzhiyun
live_virtual_bond(void * arg)4485*4882a593Smuzhiyun static int live_virtual_bond(void *arg)
4486*4882a593Smuzhiyun {
4487*4882a593Smuzhiyun static const struct phase {
4488*4882a593Smuzhiyun const char *name;
4489*4882a593Smuzhiyun unsigned int flags;
4490*4882a593Smuzhiyun } phases[] = {
4491*4882a593Smuzhiyun { "", 0 },
4492*4882a593Smuzhiyun { "schedule", BOND_SCHEDULE },
4493*4882a593Smuzhiyun { },
4494*4882a593Smuzhiyun };
4495*4882a593Smuzhiyun struct intel_gt *gt = arg;
4496*4882a593Smuzhiyun struct intel_engine_cs *siblings[MAX_ENGINE_INSTANCE + 1];
4497*4882a593Smuzhiyun unsigned int class;
4498*4882a593Smuzhiyun int err;
4499*4882a593Smuzhiyun
4500*4882a593Smuzhiyun if (intel_uc_uses_guc_submission(>->uc))
4501*4882a593Smuzhiyun return 0;
4502*4882a593Smuzhiyun
4503*4882a593Smuzhiyun for (class = 0; class <= MAX_ENGINE_CLASS; class++) {
4504*4882a593Smuzhiyun const struct phase *p;
4505*4882a593Smuzhiyun int nsibling;
4506*4882a593Smuzhiyun
4507*4882a593Smuzhiyun nsibling = select_siblings(gt, class, siblings);
4508*4882a593Smuzhiyun if (nsibling < 2)
4509*4882a593Smuzhiyun continue;
4510*4882a593Smuzhiyun
4511*4882a593Smuzhiyun for (p = phases; p->name; p++) {
4512*4882a593Smuzhiyun err = bond_virtual_engine(gt,
4513*4882a593Smuzhiyun class, siblings, nsibling,
4514*4882a593Smuzhiyun p->flags);
4515*4882a593Smuzhiyun if (err) {
4516*4882a593Smuzhiyun pr_err("%s(%s): failed class=%d, nsibling=%d, err=%d\n",
4517*4882a593Smuzhiyun __func__, p->name, class, nsibling, err);
4518*4882a593Smuzhiyun return err;
4519*4882a593Smuzhiyun }
4520*4882a593Smuzhiyun }
4521*4882a593Smuzhiyun }
4522*4882a593Smuzhiyun
4523*4882a593Smuzhiyun return 0;
4524*4882a593Smuzhiyun }
4525*4882a593Smuzhiyun
reset_virtual_engine(struct intel_gt * gt,struct intel_engine_cs ** siblings,unsigned int nsibling)4526*4882a593Smuzhiyun static int reset_virtual_engine(struct intel_gt *gt,
4527*4882a593Smuzhiyun struct intel_engine_cs **siblings,
4528*4882a593Smuzhiyun unsigned int nsibling)
4529*4882a593Smuzhiyun {
4530*4882a593Smuzhiyun struct intel_engine_cs *engine;
4531*4882a593Smuzhiyun struct intel_context *ve;
4532*4882a593Smuzhiyun struct igt_spinner spin;
4533*4882a593Smuzhiyun struct i915_request *rq;
4534*4882a593Smuzhiyun unsigned int n;
4535*4882a593Smuzhiyun int err = 0;
4536*4882a593Smuzhiyun
4537*4882a593Smuzhiyun /*
4538*4882a593Smuzhiyun * In order to support offline error capture for fast preempt reset,
4539*4882a593Smuzhiyun * we need to decouple the guilty request and ensure that it and its
4540*4882a593Smuzhiyun * descendents are not executed while the capture is in progress.
4541*4882a593Smuzhiyun */
4542*4882a593Smuzhiyun
4543*4882a593Smuzhiyun if (igt_spinner_init(&spin, gt))
4544*4882a593Smuzhiyun return -ENOMEM;
4545*4882a593Smuzhiyun
4546*4882a593Smuzhiyun ve = intel_execlists_create_virtual(siblings, nsibling);
4547*4882a593Smuzhiyun if (IS_ERR(ve)) {
4548*4882a593Smuzhiyun err = PTR_ERR(ve);
4549*4882a593Smuzhiyun goto out_spin;
4550*4882a593Smuzhiyun }
4551*4882a593Smuzhiyun
4552*4882a593Smuzhiyun for (n = 0; n < nsibling; n++)
4553*4882a593Smuzhiyun st_engine_heartbeat_disable(siblings[n]);
4554*4882a593Smuzhiyun
4555*4882a593Smuzhiyun rq = igt_spinner_create_request(&spin, ve, MI_ARB_CHECK);
4556*4882a593Smuzhiyun if (IS_ERR(rq)) {
4557*4882a593Smuzhiyun err = PTR_ERR(rq);
4558*4882a593Smuzhiyun goto out_heartbeat;
4559*4882a593Smuzhiyun }
4560*4882a593Smuzhiyun i915_request_add(rq);
4561*4882a593Smuzhiyun
4562*4882a593Smuzhiyun if (!igt_wait_for_spinner(&spin, rq)) {
4563*4882a593Smuzhiyun intel_gt_set_wedged(gt);
4564*4882a593Smuzhiyun err = -ETIME;
4565*4882a593Smuzhiyun goto out_heartbeat;
4566*4882a593Smuzhiyun }
4567*4882a593Smuzhiyun
4568*4882a593Smuzhiyun engine = rq->engine;
4569*4882a593Smuzhiyun GEM_BUG_ON(engine == ve->engine);
4570*4882a593Smuzhiyun
4571*4882a593Smuzhiyun /* Take ownership of the reset and tasklet */
4572*4882a593Smuzhiyun if (test_and_set_bit(I915_RESET_ENGINE + engine->id,
4573*4882a593Smuzhiyun >->reset.flags)) {
4574*4882a593Smuzhiyun intel_gt_set_wedged(gt);
4575*4882a593Smuzhiyun err = -EBUSY;
4576*4882a593Smuzhiyun goto out_heartbeat;
4577*4882a593Smuzhiyun }
4578*4882a593Smuzhiyun tasklet_disable(&engine->execlists.tasklet);
4579*4882a593Smuzhiyun
4580*4882a593Smuzhiyun engine->execlists.tasklet.func(engine->execlists.tasklet.data);
4581*4882a593Smuzhiyun GEM_BUG_ON(execlists_active(&engine->execlists) != rq);
4582*4882a593Smuzhiyun
4583*4882a593Smuzhiyun /* Fake a preemption event; failed of course */
4584*4882a593Smuzhiyun spin_lock_irq(&engine->active.lock);
4585*4882a593Smuzhiyun __unwind_incomplete_requests(engine);
4586*4882a593Smuzhiyun spin_unlock_irq(&engine->active.lock);
4587*4882a593Smuzhiyun GEM_BUG_ON(rq->engine != ve->engine);
4588*4882a593Smuzhiyun
4589*4882a593Smuzhiyun /* Reset the engine while keeping our active request on hold */
4590*4882a593Smuzhiyun execlists_hold(engine, rq);
4591*4882a593Smuzhiyun GEM_BUG_ON(!i915_request_on_hold(rq));
4592*4882a593Smuzhiyun
4593*4882a593Smuzhiyun intel_engine_reset(engine, NULL);
4594*4882a593Smuzhiyun GEM_BUG_ON(rq->fence.error != -EIO);
4595*4882a593Smuzhiyun
4596*4882a593Smuzhiyun /* Release our grasp on the engine, letting CS flow again */
4597*4882a593Smuzhiyun tasklet_enable(&engine->execlists.tasklet);
4598*4882a593Smuzhiyun clear_and_wake_up_bit(I915_RESET_ENGINE + engine->id, >->reset.flags);
4599*4882a593Smuzhiyun
4600*4882a593Smuzhiyun /* Check that we do not resubmit the held request */
4601*4882a593Smuzhiyun i915_request_get(rq);
4602*4882a593Smuzhiyun if (!i915_request_wait(rq, 0, HZ / 5)) {
4603*4882a593Smuzhiyun pr_err("%s: on hold request completed!\n",
4604*4882a593Smuzhiyun engine->name);
4605*4882a593Smuzhiyun intel_gt_set_wedged(gt);
4606*4882a593Smuzhiyun err = -EIO;
4607*4882a593Smuzhiyun goto out_rq;
4608*4882a593Smuzhiyun }
4609*4882a593Smuzhiyun GEM_BUG_ON(!i915_request_on_hold(rq));
4610*4882a593Smuzhiyun
4611*4882a593Smuzhiyun /* But is resubmitted on release */
4612*4882a593Smuzhiyun execlists_unhold(engine, rq);
4613*4882a593Smuzhiyun if (i915_request_wait(rq, 0, HZ / 5) < 0) {
4614*4882a593Smuzhiyun pr_err("%s: held request did not complete!\n",
4615*4882a593Smuzhiyun engine->name);
4616*4882a593Smuzhiyun intel_gt_set_wedged(gt);
4617*4882a593Smuzhiyun err = -ETIME;
4618*4882a593Smuzhiyun }
4619*4882a593Smuzhiyun
4620*4882a593Smuzhiyun out_rq:
4621*4882a593Smuzhiyun i915_request_put(rq);
4622*4882a593Smuzhiyun out_heartbeat:
4623*4882a593Smuzhiyun for (n = 0; n < nsibling; n++)
4624*4882a593Smuzhiyun st_engine_heartbeat_enable(siblings[n]);
4625*4882a593Smuzhiyun
4626*4882a593Smuzhiyun intel_context_put(ve);
4627*4882a593Smuzhiyun out_spin:
4628*4882a593Smuzhiyun igt_spinner_fini(&spin);
4629*4882a593Smuzhiyun return err;
4630*4882a593Smuzhiyun }
4631*4882a593Smuzhiyun
live_virtual_reset(void * arg)4632*4882a593Smuzhiyun static int live_virtual_reset(void *arg)
4633*4882a593Smuzhiyun {
4634*4882a593Smuzhiyun struct intel_gt *gt = arg;
4635*4882a593Smuzhiyun struct intel_engine_cs *siblings[MAX_ENGINE_INSTANCE + 1];
4636*4882a593Smuzhiyun unsigned int class;
4637*4882a593Smuzhiyun
4638*4882a593Smuzhiyun /*
4639*4882a593Smuzhiyun * Check that we handle a reset event within a virtual engine.
4640*4882a593Smuzhiyun * Only the physical engine is reset, but we have to check the flow
4641*4882a593Smuzhiyun * of the virtual requests around the reset, and make sure it is not
4642*4882a593Smuzhiyun * forgotten.
4643*4882a593Smuzhiyun */
4644*4882a593Smuzhiyun
4645*4882a593Smuzhiyun if (intel_uc_uses_guc_submission(>->uc))
4646*4882a593Smuzhiyun return 0;
4647*4882a593Smuzhiyun
4648*4882a593Smuzhiyun if (!intel_has_reset_engine(gt))
4649*4882a593Smuzhiyun return 0;
4650*4882a593Smuzhiyun
4651*4882a593Smuzhiyun for (class = 0; class <= MAX_ENGINE_CLASS; class++) {
4652*4882a593Smuzhiyun int nsibling, err;
4653*4882a593Smuzhiyun
4654*4882a593Smuzhiyun nsibling = select_siblings(gt, class, siblings);
4655*4882a593Smuzhiyun if (nsibling < 2)
4656*4882a593Smuzhiyun continue;
4657*4882a593Smuzhiyun
4658*4882a593Smuzhiyun err = reset_virtual_engine(gt, siblings, nsibling);
4659*4882a593Smuzhiyun if (err)
4660*4882a593Smuzhiyun return err;
4661*4882a593Smuzhiyun }
4662*4882a593Smuzhiyun
4663*4882a593Smuzhiyun return 0;
4664*4882a593Smuzhiyun }
4665*4882a593Smuzhiyun
intel_execlists_live_selftests(struct drm_i915_private * i915)4666*4882a593Smuzhiyun int intel_execlists_live_selftests(struct drm_i915_private *i915)
4667*4882a593Smuzhiyun {
4668*4882a593Smuzhiyun static const struct i915_subtest tests[] = {
4669*4882a593Smuzhiyun SUBTEST(live_sanitycheck),
4670*4882a593Smuzhiyun SUBTEST(live_unlite_switch),
4671*4882a593Smuzhiyun SUBTEST(live_unlite_preempt),
4672*4882a593Smuzhiyun SUBTEST(live_unlite_ring),
4673*4882a593Smuzhiyun SUBTEST(live_pin_rewind),
4674*4882a593Smuzhiyun SUBTEST(live_hold_reset),
4675*4882a593Smuzhiyun SUBTEST(live_error_interrupt),
4676*4882a593Smuzhiyun SUBTEST(live_timeslice_preempt),
4677*4882a593Smuzhiyun SUBTEST(live_timeslice_rewind),
4678*4882a593Smuzhiyun SUBTEST(live_timeslice_queue),
4679*4882a593Smuzhiyun SUBTEST(live_timeslice_nopreempt),
4680*4882a593Smuzhiyun SUBTEST(live_busywait_preempt),
4681*4882a593Smuzhiyun SUBTEST(live_preempt),
4682*4882a593Smuzhiyun SUBTEST(live_late_preempt),
4683*4882a593Smuzhiyun SUBTEST(live_nopreempt),
4684*4882a593Smuzhiyun SUBTEST(live_preempt_cancel),
4685*4882a593Smuzhiyun SUBTEST(live_suppress_self_preempt),
4686*4882a593Smuzhiyun SUBTEST(live_chain_preempt),
4687*4882a593Smuzhiyun SUBTEST(live_preempt_ring),
4688*4882a593Smuzhiyun SUBTEST(live_preempt_gang),
4689*4882a593Smuzhiyun SUBTEST(live_preempt_timeout),
4690*4882a593Smuzhiyun SUBTEST(live_preempt_user),
4691*4882a593Smuzhiyun SUBTEST(live_preempt_smoke),
4692*4882a593Smuzhiyun SUBTEST(live_virtual_engine),
4693*4882a593Smuzhiyun SUBTEST(live_virtual_mask),
4694*4882a593Smuzhiyun SUBTEST(live_virtual_preserved),
4695*4882a593Smuzhiyun SUBTEST(live_virtual_slice),
4696*4882a593Smuzhiyun SUBTEST(live_virtual_bond),
4697*4882a593Smuzhiyun SUBTEST(live_virtual_reset),
4698*4882a593Smuzhiyun };
4699*4882a593Smuzhiyun
4700*4882a593Smuzhiyun if (!HAS_EXECLISTS(i915))
4701*4882a593Smuzhiyun return 0;
4702*4882a593Smuzhiyun
4703*4882a593Smuzhiyun if (intel_gt_is_wedged(&i915->gt))
4704*4882a593Smuzhiyun return 0;
4705*4882a593Smuzhiyun
4706*4882a593Smuzhiyun return intel_gt_live_subtests(tests, &i915->gt);
4707*4882a593Smuzhiyun }
4708*4882a593Smuzhiyun
emit_semaphore_signal(struct intel_context * ce,void * slot)4709*4882a593Smuzhiyun static int emit_semaphore_signal(struct intel_context *ce, void *slot)
4710*4882a593Smuzhiyun {
4711*4882a593Smuzhiyun const u32 offset =
4712*4882a593Smuzhiyun i915_ggtt_offset(ce->engine->status_page.vma) +
4713*4882a593Smuzhiyun offset_in_page(slot);
4714*4882a593Smuzhiyun struct i915_request *rq;
4715*4882a593Smuzhiyun u32 *cs;
4716*4882a593Smuzhiyun
4717*4882a593Smuzhiyun rq = intel_context_create_request(ce);
4718*4882a593Smuzhiyun if (IS_ERR(rq))
4719*4882a593Smuzhiyun return PTR_ERR(rq);
4720*4882a593Smuzhiyun
4721*4882a593Smuzhiyun cs = intel_ring_begin(rq, 4);
4722*4882a593Smuzhiyun if (IS_ERR(cs)) {
4723*4882a593Smuzhiyun i915_request_add(rq);
4724*4882a593Smuzhiyun return PTR_ERR(cs);
4725*4882a593Smuzhiyun }
4726*4882a593Smuzhiyun
4727*4882a593Smuzhiyun *cs++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
4728*4882a593Smuzhiyun *cs++ = offset;
4729*4882a593Smuzhiyun *cs++ = 0;
4730*4882a593Smuzhiyun *cs++ = 1;
4731*4882a593Smuzhiyun
4732*4882a593Smuzhiyun intel_ring_advance(rq, cs);
4733*4882a593Smuzhiyun
4734*4882a593Smuzhiyun rq->sched.attr.priority = I915_PRIORITY_BARRIER;
4735*4882a593Smuzhiyun i915_request_add(rq);
4736*4882a593Smuzhiyun return 0;
4737*4882a593Smuzhiyun }
4738*4882a593Smuzhiyun
context_flush(struct intel_context * ce,long timeout)4739*4882a593Smuzhiyun static int context_flush(struct intel_context *ce, long timeout)
4740*4882a593Smuzhiyun {
4741*4882a593Smuzhiyun struct i915_request *rq;
4742*4882a593Smuzhiyun struct dma_fence *fence;
4743*4882a593Smuzhiyun int err = 0;
4744*4882a593Smuzhiyun
4745*4882a593Smuzhiyun rq = intel_engine_create_kernel_request(ce->engine);
4746*4882a593Smuzhiyun if (IS_ERR(rq))
4747*4882a593Smuzhiyun return PTR_ERR(rq);
4748*4882a593Smuzhiyun
4749*4882a593Smuzhiyun fence = i915_active_fence_get(&ce->timeline->last_request);
4750*4882a593Smuzhiyun if (fence) {
4751*4882a593Smuzhiyun i915_request_await_dma_fence(rq, fence);
4752*4882a593Smuzhiyun dma_fence_put(fence);
4753*4882a593Smuzhiyun }
4754*4882a593Smuzhiyun
4755*4882a593Smuzhiyun rq = i915_request_get(rq);
4756*4882a593Smuzhiyun i915_request_add(rq);
4757*4882a593Smuzhiyun if (i915_request_wait(rq, 0, timeout) < 0)
4758*4882a593Smuzhiyun err = -ETIME;
4759*4882a593Smuzhiyun i915_request_put(rq);
4760*4882a593Smuzhiyun
4761*4882a593Smuzhiyun rmb(); /* We know the request is written, make sure all state is too! */
4762*4882a593Smuzhiyun return err;
4763*4882a593Smuzhiyun }
4764*4882a593Smuzhiyun
live_lrc_layout(void * arg)4765*4882a593Smuzhiyun static int live_lrc_layout(void *arg)
4766*4882a593Smuzhiyun {
4767*4882a593Smuzhiyun struct intel_gt *gt = arg;
4768*4882a593Smuzhiyun struct intel_engine_cs *engine;
4769*4882a593Smuzhiyun enum intel_engine_id id;
4770*4882a593Smuzhiyun u32 *lrc;
4771*4882a593Smuzhiyun int err;
4772*4882a593Smuzhiyun
4773*4882a593Smuzhiyun /*
4774*4882a593Smuzhiyun * Check the registers offsets we use to create the initial reg state
4775*4882a593Smuzhiyun * match the layout saved by HW.
4776*4882a593Smuzhiyun */
4777*4882a593Smuzhiyun
4778*4882a593Smuzhiyun lrc = kmalloc(PAGE_SIZE, GFP_KERNEL);
4779*4882a593Smuzhiyun if (!lrc)
4780*4882a593Smuzhiyun return -ENOMEM;
4781*4882a593Smuzhiyun
4782*4882a593Smuzhiyun err = 0;
4783*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
4784*4882a593Smuzhiyun u32 *hw;
4785*4882a593Smuzhiyun int dw;
4786*4882a593Smuzhiyun
4787*4882a593Smuzhiyun if (!engine->default_state)
4788*4882a593Smuzhiyun continue;
4789*4882a593Smuzhiyun
4790*4882a593Smuzhiyun hw = shmem_pin_map(engine->default_state);
4791*4882a593Smuzhiyun if (!hw) {
4792*4882a593Smuzhiyun err = -ENOMEM;
4793*4882a593Smuzhiyun break;
4794*4882a593Smuzhiyun }
4795*4882a593Smuzhiyun hw += LRC_STATE_OFFSET / sizeof(*hw);
4796*4882a593Smuzhiyun
4797*4882a593Smuzhiyun execlists_init_reg_state(memset(lrc, POISON_INUSE, PAGE_SIZE),
4798*4882a593Smuzhiyun engine->kernel_context,
4799*4882a593Smuzhiyun engine,
4800*4882a593Smuzhiyun engine->kernel_context->ring,
4801*4882a593Smuzhiyun true);
4802*4882a593Smuzhiyun
4803*4882a593Smuzhiyun dw = 0;
4804*4882a593Smuzhiyun do {
4805*4882a593Smuzhiyun u32 lri = hw[dw];
4806*4882a593Smuzhiyun
4807*4882a593Smuzhiyun if (lri == 0) {
4808*4882a593Smuzhiyun dw++;
4809*4882a593Smuzhiyun continue;
4810*4882a593Smuzhiyun }
4811*4882a593Smuzhiyun
4812*4882a593Smuzhiyun if (lrc[dw] == 0) {
4813*4882a593Smuzhiyun pr_debug("%s: skipped instruction %x at dword %d\n",
4814*4882a593Smuzhiyun engine->name, lri, dw);
4815*4882a593Smuzhiyun dw++;
4816*4882a593Smuzhiyun continue;
4817*4882a593Smuzhiyun }
4818*4882a593Smuzhiyun
4819*4882a593Smuzhiyun if ((lri & GENMASK(31, 23)) != MI_INSTR(0x22, 0)) {
4820*4882a593Smuzhiyun pr_err("%s: Expected LRI command at dword %d, found %08x\n",
4821*4882a593Smuzhiyun engine->name, dw, lri);
4822*4882a593Smuzhiyun err = -EINVAL;
4823*4882a593Smuzhiyun break;
4824*4882a593Smuzhiyun }
4825*4882a593Smuzhiyun
4826*4882a593Smuzhiyun if (lrc[dw] != lri) {
4827*4882a593Smuzhiyun pr_err("%s: LRI command mismatch at dword %d, expected %08x found %08x\n",
4828*4882a593Smuzhiyun engine->name, dw, lri, lrc[dw]);
4829*4882a593Smuzhiyun err = -EINVAL;
4830*4882a593Smuzhiyun break;
4831*4882a593Smuzhiyun }
4832*4882a593Smuzhiyun
4833*4882a593Smuzhiyun lri &= 0x7f;
4834*4882a593Smuzhiyun lri++;
4835*4882a593Smuzhiyun dw++;
4836*4882a593Smuzhiyun
4837*4882a593Smuzhiyun while (lri) {
4838*4882a593Smuzhiyun if (hw[dw] != lrc[dw]) {
4839*4882a593Smuzhiyun pr_err("%s: Different registers found at dword %d, expected %x, found %x\n",
4840*4882a593Smuzhiyun engine->name, dw, hw[dw], lrc[dw]);
4841*4882a593Smuzhiyun err = -EINVAL;
4842*4882a593Smuzhiyun break;
4843*4882a593Smuzhiyun }
4844*4882a593Smuzhiyun
4845*4882a593Smuzhiyun /*
4846*4882a593Smuzhiyun * Skip over the actual register value as we
4847*4882a593Smuzhiyun * expect that to differ.
4848*4882a593Smuzhiyun */
4849*4882a593Smuzhiyun dw += 2;
4850*4882a593Smuzhiyun lri -= 2;
4851*4882a593Smuzhiyun }
4852*4882a593Smuzhiyun } while ((lrc[dw] & ~BIT(0)) != MI_BATCH_BUFFER_END);
4853*4882a593Smuzhiyun
4854*4882a593Smuzhiyun if (err) {
4855*4882a593Smuzhiyun pr_info("%s: HW register image:\n", engine->name);
4856*4882a593Smuzhiyun igt_hexdump(hw, PAGE_SIZE);
4857*4882a593Smuzhiyun
4858*4882a593Smuzhiyun pr_info("%s: SW register image:\n", engine->name);
4859*4882a593Smuzhiyun igt_hexdump(lrc, PAGE_SIZE);
4860*4882a593Smuzhiyun }
4861*4882a593Smuzhiyun
4862*4882a593Smuzhiyun shmem_unpin_map(engine->default_state, hw);
4863*4882a593Smuzhiyun if (err)
4864*4882a593Smuzhiyun break;
4865*4882a593Smuzhiyun }
4866*4882a593Smuzhiyun
4867*4882a593Smuzhiyun kfree(lrc);
4868*4882a593Smuzhiyun return err;
4869*4882a593Smuzhiyun }
4870*4882a593Smuzhiyun
find_offset(const u32 * lri,u32 offset)4871*4882a593Smuzhiyun static int find_offset(const u32 *lri, u32 offset)
4872*4882a593Smuzhiyun {
4873*4882a593Smuzhiyun int i;
4874*4882a593Smuzhiyun
4875*4882a593Smuzhiyun for (i = 0; i < PAGE_SIZE / sizeof(u32); i++)
4876*4882a593Smuzhiyun if (lri[i] == offset)
4877*4882a593Smuzhiyun return i;
4878*4882a593Smuzhiyun
4879*4882a593Smuzhiyun return -1;
4880*4882a593Smuzhiyun }
4881*4882a593Smuzhiyun
live_lrc_fixed(void * arg)4882*4882a593Smuzhiyun static int live_lrc_fixed(void *arg)
4883*4882a593Smuzhiyun {
4884*4882a593Smuzhiyun struct intel_gt *gt = arg;
4885*4882a593Smuzhiyun struct intel_engine_cs *engine;
4886*4882a593Smuzhiyun enum intel_engine_id id;
4887*4882a593Smuzhiyun int err = 0;
4888*4882a593Smuzhiyun
4889*4882a593Smuzhiyun /*
4890*4882a593Smuzhiyun * Check the assumed register offsets match the actual locations in
4891*4882a593Smuzhiyun * the context image.
4892*4882a593Smuzhiyun */
4893*4882a593Smuzhiyun
4894*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
4895*4882a593Smuzhiyun const struct {
4896*4882a593Smuzhiyun u32 reg;
4897*4882a593Smuzhiyun u32 offset;
4898*4882a593Smuzhiyun const char *name;
4899*4882a593Smuzhiyun } tbl[] = {
4900*4882a593Smuzhiyun {
4901*4882a593Smuzhiyun i915_mmio_reg_offset(RING_START(engine->mmio_base)),
4902*4882a593Smuzhiyun CTX_RING_START - 1,
4903*4882a593Smuzhiyun "RING_START"
4904*4882a593Smuzhiyun },
4905*4882a593Smuzhiyun {
4906*4882a593Smuzhiyun i915_mmio_reg_offset(RING_CTL(engine->mmio_base)),
4907*4882a593Smuzhiyun CTX_RING_CTL - 1,
4908*4882a593Smuzhiyun "RING_CTL"
4909*4882a593Smuzhiyun },
4910*4882a593Smuzhiyun {
4911*4882a593Smuzhiyun i915_mmio_reg_offset(RING_HEAD(engine->mmio_base)),
4912*4882a593Smuzhiyun CTX_RING_HEAD - 1,
4913*4882a593Smuzhiyun "RING_HEAD"
4914*4882a593Smuzhiyun },
4915*4882a593Smuzhiyun {
4916*4882a593Smuzhiyun i915_mmio_reg_offset(RING_TAIL(engine->mmio_base)),
4917*4882a593Smuzhiyun CTX_RING_TAIL - 1,
4918*4882a593Smuzhiyun "RING_TAIL"
4919*4882a593Smuzhiyun },
4920*4882a593Smuzhiyun {
4921*4882a593Smuzhiyun i915_mmio_reg_offset(RING_MI_MODE(engine->mmio_base)),
4922*4882a593Smuzhiyun lrc_ring_mi_mode(engine),
4923*4882a593Smuzhiyun "RING_MI_MODE"
4924*4882a593Smuzhiyun },
4925*4882a593Smuzhiyun {
4926*4882a593Smuzhiyun i915_mmio_reg_offset(RING_BBSTATE(engine->mmio_base)),
4927*4882a593Smuzhiyun CTX_BB_STATE - 1,
4928*4882a593Smuzhiyun "BB_STATE"
4929*4882a593Smuzhiyun },
4930*4882a593Smuzhiyun {
4931*4882a593Smuzhiyun i915_mmio_reg_offset(RING_BB_PER_CTX_PTR(engine->mmio_base)),
4932*4882a593Smuzhiyun lrc_ring_wa_bb_per_ctx(engine),
4933*4882a593Smuzhiyun "RING_BB_PER_CTX_PTR"
4934*4882a593Smuzhiyun },
4935*4882a593Smuzhiyun {
4936*4882a593Smuzhiyun i915_mmio_reg_offset(RING_INDIRECT_CTX(engine->mmio_base)),
4937*4882a593Smuzhiyun lrc_ring_indirect_ptr(engine),
4938*4882a593Smuzhiyun "RING_INDIRECT_CTX_PTR"
4939*4882a593Smuzhiyun },
4940*4882a593Smuzhiyun {
4941*4882a593Smuzhiyun i915_mmio_reg_offset(RING_INDIRECT_CTX_OFFSET(engine->mmio_base)),
4942*4882a593Smuzhiyun lrc_ring_indirect_offset(engine),
4943*4882a593Smuzhiyun "RING_INDIRECT_CTX_OFFSET"
4944*4882a593Smuzhiyun },
4945*4882a593Smuzhiyun {
4946*4882a593Smuzhiyun i915_mmio_reg_offset(RING_CTX_TIMESTAMP(engine->mmio_base)),
4947*4882a593Smuzhiyun CTX_TIMESTAMP - 1,
4948*4882a593Smuzhiyun "RING_CTX_TIMESTAMP"
4949*4882a593Smuzhiyun },
4950*4882a593Smuzhiyun {
4951*4882a593Smuzhiyun i915_mmio_reg_offset(GEN8_RING_CS_GPR(engine->mmio_base, 0)),
4952*4882a593Smuzhiyun lrc_ring_gpr0(engine),
4953*4882a593Smuzhiyun "RING_CS_GPR0"
4954*4882a593Smuzhiyun },
4955*4882a593Smuzhiyun {
4956*4882a593Smuzhiyun i915_mmio_reg_offset(RING_CMD_BUF_CCTL(engine->mmio_base)),
4957*4882a593Smuzhiyun lrc_ring_cmd_buf_cctl(engine),
4958*4882a593Smuzhiyun "RING_CMD_BUF_CCTL"
4959*4882a593Smuzhiyun },
4960*4882a593Smuzhiyun { },
4961*4882a593Smuzhiyun }, *t;
4962*4882a593Smuzhiyun u32 *hw;
4963*4882a593Smuzhiyun
4964*4882a593Smuzhiyun if (!engine->default_state)
4965*4882a593Smuzhiyun continue;
4966*4882a593Smuzhiyun
4967*4882a593Smuzhiyun hw = shmem_pin_map(engine->default_state);
4968*4882a593Smuzhiyun if (!hw) {
4969*4882a593Smuzhiyun err = -ENOMEM;
4970*4882a593Smuzhiyun break;
4971*4882a593Smuzhiyun }
4972*4882a593Smuzhiyun hw += LRC_STATE_OFFSET / sizeof(*hw);
4973*4882a593Smuzhiyun
4974*4882a593Smuzhiyun for (t = tbl; t->name; t++) {
4975*4882a593Smuzhiyun int dw = find_offset(hw, t->reg);
4976*4882a593Smuzhiyun
4977*4882a593Smuzhiyun if (dw != t->offset) {
4978*4882a593Smuzhiyun pr_err("%s: Offset for %s [0x%x] mismatch, found %x, expected %x\n",
4979*4882a593Smuzhiyun engine->name,
4980*4882a593Smuzhiyun t->name,
4981*4882a593Smuzhiyun t->reg,
4982*4882a593Smuzhiyun dw,
4983*4882a593Smuzhiyun t->offset);
4984*4882a593Smuzhiyun err = -EINVAL;
4985*4882a593Smuzhiyun }
4986*4882a593Smuzhiyun }
4987*4882a593Smuzhiyun
4988*4882a593Smuzhiyun shmem_unpin_map(engine->default_state, hw);
4989*4882a593Smuzhiyun }
4990*4882a593Smuzhiyun
4991*4882a593Smuzhiyun return err;
4992*4882a593Smuzhiyun }
4993*4882a593Smuzhiyun
__live_lrc_state(struct intel_engine_cs * engine,struct i915_vma * scratch)4994*4882a593Smuzhiyun static int __live_lrc_state(struct intel_engine_cs *engine,
4995*4882a593Smuzhiyun struct i915_vma *scratch)
4996*4882a593Smuzhiyun {
4997*4882a593Smuzhiyun struct intel_context *ce;
4998*4882a593Smuzhiyun struct i915_request *rq;
4999*4882a593Smuzhiyun struct i915_gem_ww_ctx ww;
5000*4882a593Smuzhiyun enum {
5001*4882a593Smuzhiyun RING_START_IDX = 0,
5002*4882a593Smuzhiyun RING_TAIL_IDX,
5003*4882a593Smuzhiyun MAX_IDX
5004*4882a593Smuzhiyun };
5005*4882a593Smuzhiyun u32 expected[MAX_IDX];
5006*4882a593Smuzhiyun u32 *cs;
5007*4882a593Smuzhiyun int err;
5008*4882a593Smuzhiyun int n;
5009*4882a593Smuzhiyun
5010*4882a593Smuzhiyun ce = intel_context_create(engine);
5011*4882a593Smuzhiyun if (IS_ERR(ce))
5012*4882a593Smuzhiyun return PTR_ERR(ce);
5013*4882a593Smuzhiyun
5014*4882a593Smuzhiyun i915_gem_ww_ctx_init(&ww, false);
5015*4882a593Smuzhiyun retry:
5016*4882a593Smuzhiyun err = i915_gem_object_lock(scratch->obj, &ww);
5017*4882a593Smuzhiyun if (!err)
5018*4882a593Smuzhiyun err = intel_context_pin_ww(ce, &ww);
5019*4882a593Smuzhiyun if (err)
5020*4882a593Smuzhiyun goto err_put;
5021*4882a593Smuzhiyun
5022*4882a593Smuzhiyun rq = i915_request_create(ce);
5023*4882a593Smuzhiyun if (IS_ERR(rq)) {
5024*4882a593Smuzhiyun err = PTR_ERR(rq);
5025*4882a593Smuzhiyun goto err_unpin;
5026*4882a593Smuzhiyun }
5027*4882a593Smuzhiyun
5028*4882a593Smuzhiyun cs = intel_ring_begin(rq, 4 * MAX_IDX);
5029*4882a593Smuzhiyun if (IS_ERR(cs)) {
5030*4882a593Smuzhiyun err = PTR_ERR(cs);
5031*4882a593Smuzhiyun i915_request_add(rq);
5032*4882a593Smuzhiyun goto err_unpin;
5033*4882a593Smuzhiyun }
5034*4882a593Smuzhiyun
5035*4882a593Smuzhiyun *cs++ = MI_STORE_REGISTER_MEM_GEN8 | MI_USE_GGTT;
5036*4882a593Smuzhiyun *cs++ = i915_mmio_reg_offset(RING_START(engine->mmio_base));
5037*4882a593Smuzhiyun *cs++ = i915_ggtt_offset(scratch) + RING_START_IDX * sizeof(u32);
5038*4882a593Smuzhiyun *cs++ = 0;
5039*4882a593Smuzhiyun
5040*4882a593Smuzhiyun expected[RING_START_IDX] = i915_ggtt_offset(ce->ring->vma);
5041*4882a593Smuzhiyun
5042*4882a593Smuzhiyun *cs++ = MI_STORE_REGISTER_MEM_GEN8 | MI_USE_GGTT;
5043*4882a593Smuzhiyun *cs++ = i915_mmio_reg_offset(RING_TAIL(engine->mmio_base));
5044*4882a593Smuzhiyun *cs++ = i915_ggtt_offset(scratch) + RING_TAIL_IDX * sizeof(u32);
5045*4882a593Smuzhiyun *cs++ = 0;
5046*4882a593Smuzhiyun
5047*4882a593Smuzhiyun err = i915_request_await_object(rq, scratch->obj, true);
5048*4882a593Smuzhiyun if (!err)
5049*4882a593Smuzhiyun err = i915_vma_move_to_active(scratch, rq, EXEC_OBJECT_WRITE);
5050*4882a593Smuzhiyun
5051*4882a593Smuzhiyun i915_request_get(rq);
5052*4882a593Smuzhiyun i915_request_add(rq);
5053*4882a593Smuzhiyun if (err)
5054*4882a593Smuzhiyun goto err_rq;
5055*4882a593Smuzhiyun
5056*4882a593Smuzhiyun intel_engine_flush_submission(engine);
5057*4882a593Smuzhiyun expected[RING_TAIL_IDX] = ce->ring->tail;
5058*4882a593Smuzhiyun
5059*4882a593Smuzhiyun if (i915_request_wait(rq, 0, HZ / 5) < 0) {
5060*4882a593Smuzhiyun err = -ETIME;
5061*4882a593Smuzhiyun goto err_rq;
5062*4882a593Smuzhiyun }
5063*4882a593Smuzhiyun
5064*4882a593Smuzhiyun cs = i915_gem_object_pin_map(scratch->obj, I915_MAP_WB);
5065*4882a593Smuzhiyun if (IS_ERR(cs)) {
5066*4882a593Smuzhiyun err = PTR_ERR(cs);
5067*4882a593Smuzhiyun goto err_rq;
5068*4882a593Smuzhiyun }
5069*4882a593Smuzhiyun
5070*4882a593Smuzhiyun for (n = 0; n < MAX_IDX; n++) {
5071*4882a593Smuzhiyun if (cs[n] != expected[n]) {
5072*4882a593Smuzhiyun pr_err("%s: Stored register[%d] value[0x%x] did not match expected[0x%x]\n",
5073*4882a593Smuzhiyun engine->name, n, cs[n], expected[n]);
5074*4882a593Smuzhiyun err = -EINVAL;
5075*4882a593Smuzhiyun break;
5076*4882a593Smuzhiyun }
5077*4882a593Smuzhiyun }
5078*4882a593Smuzhiyun
5079*4882a593Smuzhiyun i915_gem_object_unpin_map(scratch->obj);
5080*4882a593Smuzhiyun
5081*4882a593Smuzhiyun err_rq:
5082*4882a593Smuzhiyun i915_request_put(rq);
5083*4882a593Smuzhiyun err_unpin:
5084*4882a593Smuzhiyun intel_context_unpin(ce);
5085*4882a593Smuzhiyun err_put:
5086*4882a593Smuzhiyun if (err == -EDEADLK) {
5087*4882a593Smuzhiyun err = i915_gem_ww_ctx_backoff(&ww);
5088*4882a593Smuzhiyun if (!err)
5089*4882a593Smuzhiyun goto retry;
5090*4882a593Smuzhiyun }
5091*4882a593Smuzhiyun i915_gem_ww_ctx_fini(&ww);
5092*4882a593Smuzhiyun intel_context_put(ce);
5093*4882a593Smuzhiyun return err;
5094*4882a593Smuzhiyun }
5095*4882a593Smuzhiyun
live_lrc_state(void * arg)5096*4882a593Smuzhiyun static int live_lrc_state(void *arg)
5097*4882a593Smuzhiyun {
5098*4882a593Smuzhiyun struct intel_gt *gt = arg;
5099*4882a593Smuzhiyun struct intel_engine_cs *engine;
5100*4882a593Smuzhiyun struct i915_vma *scratch;
5101*4882a593Smuzhiyun enum intel_engine_id id;
5102*4882a593Smuzhiyun int err = 0;
5103*4882a593Smuzhiyun
5104*4882a593Smuzhiyun /*
5105*4882a593Smuzhiyun * Check the live register state matches what we expect for this
5106*4882a593Smuzhiyun * intel_context.
5107*4882a593Smuzhiyun */
5108*4882a593Smuzhiyun
5109*4882a593Smuzhiyun scratch = create_scratch(gt);
5110*4882a593Smuzhiyun if (IS_ERR(scratch))
5111*4882a593Smuzhiyun return PTR_ERR(scratch);
5112*4882a593Smuzhiyun
5113*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
5114*4882a593Smuzhiyun err = __live_lrc_state(engine, scratch);
5115*4882a593Smuzhiyun if (err)
5116*4882a593Smuzhiyun break;
5117*4882a593Smuzhiyun }
5118*4882a593Smuzhiyun
5119*4882a593Smuzhiyun if (igt_flush_test(gt->i915))
5120*4882a593Smuzhiyun err = -EIO;
5121*4882a593Smuzhiyun
5122*4882a593Smuzhiyun i915_vma_unpin_and_release(&scratch, 0);
5123*4882a593Smuzhiyun return err;
5124*4882a593Smuzhiyun }
5125*4882a593Smuzhiyun
gpr_make_dirty(struct intel_context * ce)5126*4882a593Smuzhiyun static int gpr_make_dirty(struct intel_context *ce)
5127*4882a593Smuzhiyun {
5128*4882a593Smuzhiyun struct i915_request *rq;
5129*4882a593Smuzhiyun u32 *cs;
5130*4882a593Smuzhiyun int n;
5131*4882a593Smuzhiyun
5132*4882a593Smuzhiyun rq = intel_context_create_request(ce);
5133*4882a593Smuzhiyun if (IS_ERR(rq))
5134*4882a593Smuzhiyun return PTR_ERR(rq);
5135*4882a593Smuzhiyun
5136*4882a593Smuzhiyun cs = intel_ring_begin(rq, 2 * NUM_GPR_DW + 2);
5137*4882a593Smuzhiyun if (IS_ERR(cs)) {
5138*4882a593Smuzhiyun i915_request_add(rq);
5139*4882a593Smuzhiyun return PTR_ERR(cs);
5140*4882a593Smuzhiyun }
5141*4882a593Smuzhiyun
5142*4882a593Smuzhiyun *cs++ = MI_LOAD_REGISTER_IMM(NUM_GPR_DW);
5143*4882a593Smuzhiyun for (n = 0; n < NUM_GPR_DW; n++) {
5144*4882a593Smuzhiyun *cs++ = CS_GPR(ce->engine, n);
5145*4882a593Smuzhiyun *cs++ = STACK_MAGIC;
5146*4882a593Smuzhiyun }
5147*4882a593Smuzhiyun *cs++ = MI_NOOP;
5148*4882a593Smuzhiyun
5149*4882a593Smuzhiyun intel_ring_advance(rq, cs);
5150*4882a593Smuzhiyun
5151*4882a593Smuzhiyun rq->sched.attr.priority = I915_PRIORITY_BARRIER;
5152*4882a593Smuzhiyun i915_request_add(rq);
5153*4882a593Smuzhiyun
5154*4882a593Smuzhiyun return 0;
5155*4882a593Smuzhiyun }
5156*4882a593Smuzhiyun
5157*4882a593Smuzhiyun static struct i915_request *
__gpr_read(struct intel_context * ce,struct i915_vma * scratch,u32 * slot)5158*4882a593Smuzhiyun __gpr_read(struct intel_context *ce, struct i915_vma *scratch, u32 *slot)
5159*4882a593Smuzhiyun {
5160*4882a593Smuzhiyun const u32 offset =
5161*4882a593Smuzhiyun i915_ggtt_offset(ce->engine->status_page.vma) +
5162*4882a593Smuzhiyun offset_in_page(slot);
5163*4882a593Smuzhiyun struct i915_request *rq;
5164*4882a593Smuzhiyun u32 *cs;
5165*4882a593Smuzhiyun int err;
5166*4882a593Smuzhiyun int n;
5167*4882a593Smuzhiyun
5168*4882a593Smuzhiyun rq = intel_context_create_request(ce);
5169*4882a593Smuzhiyun if (IS_ERR(rq))
5170*4882a593Smuzhiyun return rq;
5171*4882a593Smuzhiyun
5172*4882a593Smuzhiyun cs = intel_ring_begin(rq, 6 + 4 * NUM_GPR_DW);
5173*4882a593Smuzhiyun if (IS_ERR(cs)) {
5174*4882a593Smuzhiyun i915_request_add(rq);
5175*4882a593Smuzhiyun return ERR_CAST(cs);
5176*4882a593Smuzhiyun }
5177*4882a593Smuzhiyun
5178*4882a593Smuzhiyun *cs++ = MI_ARB_ON_OFF | MI_ARB_ENABLE;
5179*4882a593Smuzhiyun *cs++ = MI_NOOP;
5180*4882a593Smuzhiyun
5181*4882a593Smuzhiyun *cs++ = MI_SEMAPHORE_WAIT |
5182*4882a593Smuzhiyun MI_SEMAPHORE_GLOBAL_GTT |
5183*4882a593Smuzhiyun MI_SEMAPHORE_POLL |
5184*4882a593Smuzhiyun MI_SEMAPHORE_SAD_NEQ_SDD;
5185*4882a593Smuzhiyun *cs++ = 0;
5186*4882a593Smuzhiyun *cs++ = offset;
5187*4882a593Smuzhiyun *cs++ = 0;
5188*4882a593Smuzhiyun
5189*4882a593Smuzhiyun for (n = 0; n < NUM_GPR_DW; n++) {
5190*4882a593Smuzhiyun *cs++ = MI_STORE_REGISTER_MEM_GEN8 | MI_USE_GGTT;
5191*4882a593Smuzhiyun *cs++ = CS_GPR(ce->engine, n);
5192*4882a593Smuzhiyun *cs++ = i915_ggtt_offset(scratch) + n * sizeof(u32);
5193*4882a593Smuzhiyun *cs++ = 0;
5194*4882a593Smuzhiyun }
5195*4882a593Smuzhiyun
5196*4882a593Smuzhiyun i915_vma_lock(scratch);
5197*4882a593Smuzhiyun err = i915_request_await_object(rq, scratch->obj, true);
5198*4882a593Smuzhiyun if (!err)
5199*4882a593Smuzhiyun err = i915_vma_move_to_active(scratch, rq, EXEC_OBJECT_WRITE);
5200*4882a593Smuzhiyun i915_vma_unlock(scratch);
5201*4882a593Smuzhiyun
5202*4882a593Smuzhiyun i915_request_get(rq);
5203*4882a593Smuzhiyun i915_request_add(rq);
5204*4882a593Smuzhiyun if (err) {
5205*4882a593Smuzhiyun i915_request_put(rq);
5206*4882a593Smuzhiyun rq = ERR_PTR(err);
5207*4882a593Smuzhiyun }
5208*4882a593Smuzhiyun
5209*4882a593Smuzhiyun return rq;
5210*4882a593Smuzhiyun }
5211*4882a593Smuzhiyun
__live_lrc_gpr(struct intel_engine_cs * engine,struct i915_vma * scratch,bool preempt)5212*4882a593Smuzhiyun static int __live_lrc_gpr(struct intel_engine_cs *engine,
5213*4882a593Smuzhiyun struct i915_vma *scratch,
5214*4882a593Smuzhiyun bool preempt)
5215*4882a593Smuzhiyun {
5216*4882a593Smuzhiyun u32 *slot = memset32(engine->status_page.addr + 1000, 0, 4);
5217*4882a593Smuzhiyun struct intel_context *ce;
5218*4882a593Smuzhiyun struct i915_request *rq;
5219*4882a593Smuzhiyun u32 *cs;
5220*4882a593Smuzhiyun int err;
5221*4882a593Smuzhiyun int n;
5222*4882a593Smuzhiyun
5223*4882a593Smuzhiyun if (INTEL_GEN(engine->i915) < 9 && engine->class != RENDER_CLASS)
5224*4882a593Smuzhiyun return 0; /* GPR only on rcs0 for gen8 */
5225*4882a593Smuzhiyun
5226*4882a593Smuzhiyun err = gpr_make_dirty(engine->kernel_context);
5227*4882a593Smuzhiyun if (err)
5228*4882a593Smuzhiyun return err;
5229*4882a593Smuzhiyun
5230*4882a593Smuzhiyun ce = intel_context_create(engine);
5231*4882a593Smuzhiyun if (IS_ERR(ce))
5232*4882a593Smuzhiyun return PTR_ERR(ce);
5233*4882a593Smuzhiyun
5234*4882a593Smuzhiyun rq = __gpr_read(ce, scratch, slot);
5235*4882a593Smuzhiyun if (IS_ERR(rq)) {
5236*4882a593Smuzhiyun err = PTR_ERR(rq);
5237*4882a593Smuzhiyun goto err_put;
5238*4882a593Smuzhiyun }
5239*4882a593Smuzhiyun
5240*4882a593Smuzhiyun err = wait_for_submit(engine, rq, HZ / 2);
5241*4882a593Smuzhiyun if (err)
5242*4882a593Smuzhiyun goto err_rq;
5243*4882a593Smuzhiyun
5244*4882a593Smuzhiyun if (preempt) {
5245*4882a593Smuzhiyun err = gpr_make_dirty(engine->kernel_context);
5246*4882a593Smuzhiyun if (err)
5247*4882a593Smuzhiyun goto err_rq;
5248*4882a593Smuzhiyun
5249*4882a593Smuzhiyun err = emit_semaphore_signal(engine->kernel_context, slot);
5250*4882a593Smuzhiyun if (err)
5251*4882a593Smuzhiyun goto err_rq;
5252*4882a593Smuzhiyun } else {
5253*4882a593Smuzhiyun slot[0] = 1;
5254*4882a593Smuzhiyun wmb();
5255*4882a593Smuzhiyun }
5256*4882a593Smuzhiyun
5257*4882a593Smuzhiyun if (i915_request_wait(rq, 0, HZ / 5) < 0) {
5258*4882a593Smuzhiyun err = -ETIME;
5259*4882a593Smuzhiyun goto err_rq;
5260*4882a593Smuzhiyun }
5261*4882a593Smuzhiyun
5262*4882a593Smuzhiyun cs = i915_gem_object_pin_map(scratch->obj, I915_MAP_WB);
5263*4882a593Smuzhiyun if (IS_ERR(cs)) {
5264*4882a593Smuzhiyun err = PTR_ERR(cs);
5265*4882a593Smuzhiyun goto err_rq;
5266*4882a593Smuzhiyun }
5267*4882a593Smuzhiyun
5268*4882a593Smuzhiyun for (n = 0; n < NUM_GPR_DW; n++) {
5269*4882a593Smuzhiyun if (cs[n]) {
5270*4882a593Smuzhiyun pr_err("%s: GPR[%d].%s was not zero, found 0x%08x!\n",
5271*4882a593Smuzhiyun engine->name,
5272*4882a593Smuzhiyun n / 2, n & 1 ? "udw" : "ldw",
5273*4882a593Smuzhiyun cs[n]);
5274*4882a593Smuzhiyun err = -EINVAL;
5275*4882a593Smuzhiyun break;
5276*4882a593Smuzhiyun }
5277*4882a593Smuzhiyun }
5278*4882a593Smuzhiyun
5279*4882a593Smuzhiyun i915_gem_object_unpin_map(scratch->obj);
5280*4882a593Smuzhiyun
5281*4882a593Smuzhiyun err_rq:
5282*4882a593Smuzhiyun memset32(&slot[0], -1, 4);
5283*4882a593Smuzhiyun wmb();
5284*4882a593Smuzhiyun i915_request_put(rq);
5285*4882a593Smuzhiyun err_put:
5286*4882a593Smuzhiyun intel_context_put(ce);
5287*4882a593Smuzhiyun return err;
5288*4882a593Smuzhiyun }
5289*4882a593Smuzhiyun
live_lrc_gpr(void * arg)5290*4882a593Smuzhiyun static int live_lrc_gpr(void *arg)
5291*4882a593Smuzhiyun {
5292*4882a593Smuzhiyun struct intel_gt *gt = arg;
5293*4882a593Smuzhiyun struct intel_engine_cs *engine;
5294*4882a593Smuzhiyun struct i915_vma *scratch;
5295*4882a593Smuzhiyun enum intel_engine_id id;
5296*4882a593Smuzhiyun int err = 0;
5297*4882a593Smuzhiyun
5298*4882a593Smuzhiyun /*
5299*4882a593Smuzhiyun * Check that GPR registers are cleared in new contexts as we need
5300*4882a593Smuzhiyun * to avoid leaking any information from previous contexts.
5301*4882a593Smuzhiyun */
5302*4882a593Smuzhiyun
5303*4882a593Smuzhiyun scratch = create_scratch(gt);
5304*4882a593Smuzhiyun if (IS_ERR(scratch))
5305*4882a593Smuzhiyun return PTR_ERR(scratch);
5306*4882a593Smuzhiyun
5307*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
5308*4882a593Smuzhiyun st_engine_heartbeat_disable(engine);
5309*4882a593Smuzhiyun
5310*4882a593Smuzhiyun err = __live_lrc_gpr(engine, scratch, false);
5311*4882a593Smuzhiyun if (err)
5312*4882a593Smuzhiyun goto err;
5313*4882a593Smuzhiyun
5314*4882a593Smuzhiyun err = __live_lrc_gpr(engine, scratch, true);
5315*4882a593Smuzhiyun if (err)
5316*4882a593Smuzhiyun goto err;
5317*4882a593Smuzhiyun
5318*4882a593Smuzhiyun err:
5319*4882a593Smuzhiyun st_engine_heartbeat_enable(engine);
5320*4882a593Smuzhiyun if (igt_flush_test(gt->i915))
5321*4882a593Smuzhiyun err = -EIO;
5322*4882a593Smuzhiyun if (err)
5323*4882a593Smuzhiyun break;
5324*4882a593Smuzhiyun }
5325*4882a593Smuzhiyun
5326*4882a593Smuzhiyun i915_vma_unpin_and_release(&scratch, 0);
5327*4882a593Smuzhiyun return err;
5328*4882a593Smuzhiyun }
5329*4882a593Smuzhiyun
5330*4882a593Smuzhiyun static struct i915_request *
create_timestamp(struct intel_context * ce,void * slot,int idx)5331*4882a593Smuzhiyun create_timestamp(struct intel_context *ce, void *slot, int idx)
5332*4882a593Smuzhiyun {
5333*4882a593Smuzhiyun const u32 offset =
5334*4882a593Smuzhiyun i915_ggtt_offset(ce->engine->status_page.vma) +
5335*4882a593Smuzhiyun offset_in_page(slot);
5336*4882a593Smuzhiyun struct i915_request *rq;
5337*4882a593Smuzhiyun u32 *cs;
5338*4882a593Smuzhiyun int err;
5339*4882a593Smuzhiyun
5340*4882a593Smuzhiyun rq = intel_context_create_request(ce);
5341*4882a593Smuzhiyun if (IS_ERR(rq))
5342*4882a593Smuzhiyun return rq;
5343*4882a593Smuzhiyun
5344*4882a593Smuzhiyun cs = intel_ring_begin(rq, 10);
5345*4882a593Smuzhiyun if (IS_ERR(cs)) {
5346*4882a593Smuzhiyun err = PTR_ERR(cs);
5347*4882a593Smuzhiyun goto err;
5348*4882a593Smuzhiyun }
5349*4882a593Smuzhiyun
5350*4882a593Smuzhiyun *cs++ = MI_ARB_ON_OFF | MI_ARB_ENABLE;
5351*4882a593Smuzhiyun *cs++ = MI_NOOP;
5352*4882a593Smuzhiyun
5353*4882a593Smuzhiyun *cs++ = MI_SEMAPHORE_WAIT |
5354*4882a593Smuzhiyun MI_SEMAPHORE_GLOBAL_GTT |
5355*4882a593Smuzhiyun MI_SEMAPHORE_POLL |
5356*4882a593Smuzhiyun MI_SEMAPHORE_SAD_NEQ_SDD;
5357*4882a593Smuzhiyun *cs++ = 0;
5358*4882a593Smuzhiyun *cs++ = offset;
5359*4882a593Smuzhiyun *cs++ = 0;
5360*4882a593Smuzhiyun
5361*4882a593Smuzhiyun *cs++ = MI_STORE_REGISTER_MEM_GEN8 | MI_USE_GGTT;
5362*4882a593Smuzhiyun *cs++ = i915_mmio_reg_offset(RING_CTX_TIMESTAMP(rq->engine->mmio_base));
5363*4882a593Smuzhiyun *cs++ = offset + idx * sizeof(u32);
5364*4882a593Smuzhiyun *cs++ = 0;
5365*4882a593Smuzhiyun
5366*4882a593Smuzhiyun intel_ring_advance(rq, cs);
5367*4882a593Smuzhiyun
5368*4882a593Smuzhiyun rq->sched.attr.priority = I915_PRIORITY_MASK;
5369*4882a593Smuzhiyun err = 0;
5370*4882a593Smuzhiyun err:
5371*4882a593Smuzhiyun i915_request_get(rq);
5372*4882a593Smuzhiyun i915_request_add(rq);
5373*4882a593Smuzhiyun if (err) {
5374*4882a593Smuzhiyun i915_request_put(rq);
5375*4882a593Smuzhiyun return ERR_PTR(err);
5376*4882a593Smuzhiyun }
5377*4882a593Smuzhiyun
5378*4882a593Smuzhiyun return rq;
5379*4882a593Smuzhiyun }
5380*4882a593Smuzhiyun
5381*4882a593Smuzhiyun struct lrc_timestamp {
5382*4882a593Smuzhiyun struct intel_engine_cs *engine;
5383*4882a593Smuzhiyun struct intel_context *ce[2];
5384*4882a593Smuzhiyun u32 poison;
5385*4882a593Smuzhiyun };
5386*4882a593Smuzhiyun
timestamp_advanced(u32 start,u32 end)5387*4882a593Smuzhiyun static bool timestamp_advanced(u32 start, u32 end)
5388*4882a593Smuzhiyun {
5389*4882a593Smuzhiyun return (s32)(end - start) > 0;
5390*4882a593Smuzhiyun }
5391*4882a593Smuzhiyun
__lrc_timestamp(const struct lrc_timestamp * arg,bool preempt)5392*4882a593Smuzhiyun static int __lrc_timestamp(const struct lrc_timestamp *arg, bool preempt)
5393*4882a593Smuzhiyun {
5394*4882a593Smuzhiyun u32 *slot = memset32(arg->engine->status_page.addr + 1000, 0, 4);
5395*4882a593Smuzhiyun struct i915_request *rq;
5396*4882a593Smuzhiyun u32 timestamp;
5397*4882a593Smuzhiyun int err = 0;
5398*4882a593Smuzhiyun
5399*4882a593Smuzhiyun arg->ce[0]->lrc_reg_state[CTX_TIMESTAMP] = arg->poison;
5400*4882a593Smuzhiyun rq = create_timestamp(arg->ce[0], slot, 1);
5401*4882a593Smuzhiyun if (IS_ERR(rq))
5402*4882a593Smuzhiyun return PTR_ERR(rq);
5403*4882a593Smuzhiyun
5404*4882a593Smuzhiyun err = wait_for_submit(rq->engine, rq, HZ / 2);
5405*4882a593Smuzhiyun if (err)
5406*4882a593Smuzhiyun goto err;
5407*4882a593Smuzhiyun
5408*4882a593Smuzhiyun if (preempt) {
5409*4882a593Smuzhiyun arg->ce[1]->lrc_reg_state[CTX_TIMESTAMP] = 0xdeadbeef;
5410*4882a593Smuzhiyun err = emit_semaphore_signal(arg->ce[1], slot);
5411*4882a593Smuzhiyun if (err)
5412*4882a593Smuzhiyun goto err;
5413*4882a593Smuzhiyun } else {
5414*4882a593Smuzhiyun slot[0] = 1;
5415*4882a593Smuzhiyun wmb();
5416*4882a593Smuzhiyun }
5417*4882a593Smuzhiyun
5418*4882a593Smuzhiyun /* And wait for switch to kernel (to save our context to memory) */
5419*4882a593Smuzhiyun err = context_flush(arg->ce[0], HZ / 2);
5420*4882a593Smuzhiyun if (err)
5421*4882a593Smuzhiyun goto err;
5422*4882a593Smuzhiyun
5423*4882a593Smuzhiyun if (!timestamp_advanced(arg->poison, slot[1])) {
5424*4882a593Smuzhiyun pr_err("%s(%s): invalid timestamp on restore, context:%x, request:%x\n",
5425*4882a593Smuzhiyun arg->engine->name, preempt ? "preempt" : "simple",
5426*4882a593Smuzhiyun arg->poison, slot[1]);
5427*4882a593Smuzhiyun err = -EINVAL;
5428*4882a593Smuzhiyun }
5429*4882a593Smuzhiyun
5430*4882a593Smuzhiyun timestamp = READ_ONCE(arg->ce[0]->lrc_reg_state[CTX_TIMESTAMP]);
5431*4882a593Smuzhiyun if (!timestamp_advanced(slot[1], timestamp)) {
5432*4882a593Smuzhiyun pr_err("%s(%s): invalid timestamp on save, request:%x, context:%x\n",
5433*4882a593Smuzhiyun arg->engine->name, preempt ? "preempt" : "simple",
5434*4882a593Smuzhiyun slot[1], timestamp);
5435*4882a593Smuzhiyun err = -EINVAL;
5436*4882a593Smuzhiyun }
5437*4882a593Smuzhiyun
5438*4882a593Smuzhiyun err:
5439*4882a593Smuzhiyun memset32(slot, -1, 4);
5440*4882a593Smuzhiyun i915_request_put(rq);
5441*4882a593Smuzhiyun return err;
5442*4882a593Smuzhiyun }
5443*4882a593Smuzhiyun
live_lrc_timestamp(void * arg)5444*4882a593Smuzhiyun static int live_lrc_timestamp(void *arg)
5445*4882a593Smuzhiyun {
5446*4882a593Smuzhiyun struct lrc_timestamp data = {};
5447*4882a593Smuzhiyun struct intel_gt *gt = arg;
5448*4882a593Smuzhiyun enum intel_engine_id id;
5449*4882a593Smuzhiyun const u32 poison[] = {
5450*4882a593Smuzhiyun 0,
5451*4882a593Smuzhiyun S32_MAX,
5452*4882a593Smuzhiyun (u32)S32_MAX + 1,
5453*4882a593Smuzhiyun U32_MAX,
5454*4882a593Smuzhiyun };
5455*4882a593Smuzhiyun
5456*4882a593Smuzhiyun /*
5457*4882a593Smuzhiyun * We want to verify that the timestamp is saved and restore across
5458*4882a593Smuzhiyun * context switches and is monotonic.
5459*4882a593Smuzhiyun *
5460*4882a593Smuzhiyun * So we do this with a little bit of LRC poisoning to check various
5461*4882a593Smuzhiyun * boundary conditions, and see what happens if we preempt the context
5462*4882a593Smuzhiyun * with a second request (carrying more poison into the timestamp).
5463*4882a593Smuzhiyun */
5464*4882a593Smuzhiyun
5465*4882a593Smuzhiyun for_each_engine(data.engine, gt, id) {
5466*4882a593Smuzhiyun int i, err = 0;
5467*4882a593Smuzhiyun
5468*4882a593Smuzhiyun st_engine_heartbeat_disable(data.engine);
5469*4882a593Smuzhiyun
5470*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(data.ce); i++) {
5471*4882a593Smuzhiyun struct intel_context *tmp;
5472*4882a593Smuzhiyun
5473*4882a593Smuzhiyun tmp = intel_context_create(data.engine);
5474*4882a593Smuzhiyun if (IS_ERR(tmp)) {
5475*4882a593Smuzhiyun err = PTR_ERR(tmp);
5476*4882a593Smuzhiyun goto err;
5477*4882a593Smuzhiyun }
5478*4882a593Smuzhiyun
5479*4882a593Smuzhiyun err = intel_context_pin(tmp);
5480*4882a593Smuzhiyun if (err) {
5481*4882a593Smuzhiyun intel_context_put(tmp);
5482*4882a593Smuzhiyun goto err;
5483*4882a593Smuzhiyun }
5484*4882a593Smuzhiyun
5485*4882a593Smuzhiyun data.ce[i] = tmp;
5486*4882a593Smuzhiyun }
5487*4882a593Smuzhiyun
5488*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(poison); i++) {
5489*4882a593Smuzhiyun data.poison = poison[i];
5490*4882a593Smuzhiyun
5491*4882a593Smuzhiyun err = __lrc_timestamp(&data, false);
5492*4882a593Smuzhiyun if (err)
5493*4882a593Smuzhiyun break;
5494*4882a593Smuzhiyun
5495*4882a593Smuzhiyun err = __lrc_timestamp(&data, true);
5496*4882a593Smuzhiyun if (err)
5497*4882a593Smuzhiyun break;
5498*4882a593Smuzhiyun }
5499*4882a593Smuzhiyun
5500*4882a593Smuzhiyun err:
5501*4882a593Smuzhiyun st_engine_heartbeat_enable(data.engine);
5502*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(data.ce); i++) {
5503*4882a593Smuzhiyun if (!data.ce[i])
5504*4882a593Smuzhiyun break;
5505*4882a593Smuzhiyun
5506*4882a593Smuzhiyun intel_context_unpin(data.ce[i]);
5507*4882a593Smuzhiyun intel_context_put(data.ce[i]);
5508*4882a593Smuzhiyun }
5509*4882a593Smuzhiyun
5510*4882a593Smuzhiyun if (igt_flush_test(gt->i915))
5511*4882a593Smuzhiyun err = -EIO;
5512*4882a593Smuzhiyun if (err)
5513*4882a593Smuzhiyun return err;
5514*4882a593Smuzhiyun }
5515*4882a593Smuzhiyun
5516*4882a593Smuzhiyun return 0;
5517*4882a593Smuzhiyun }
5518*4882a593Smuzhiyun
5519*4882a593Smuzhiyun static struct i915_vma *
create_user_vma(struct i915_address_space * vm,unsigned long size)5520*4882a593Smuzhiyun create_user_vma(struct i915_address_space *vm, unsigned long size)
5521*4882a593Smuzhiyun {
5522*4882a593Smuzhiyun struct drm_i915_gem_object *obj;
5523*4882a593Smuzhiyun struct i915_vma *vma;
5524*4882a593Smuzhiyun int err;
5525*4882a593Smuzhiyun
5526*4882a593Smuzhiyun obj = i915_gem_object_create_internal(vm->i915, size);
5527*4882a593Smuzhiyun if (IS_ERR(obj))
5528*4882a593Smuzhiyun return ERR_CAST(obj);
5529*4882a593Smuzhiyun
5530*4882a593Smuzhiyun vma = i915_vma_instance(obj, vm, NULL);
5531*4882a593Smuzhiyun if (IS_ERR(vma)) {
5532*4882a593Smuzhiyun i915_gem_object_put(obj);
5533*4882a593Smuzhiyun return vma;
5534*4882a593Smuzhiyun }
5535*4882a593Smuzhiyun
5536*4882a593Smuzhiyun err = i915_vma_pin(vma, 0, 0, PIN_USER);
5537*4882a593Smuzhiyun if (err) {
5538*4882a593Smuzhiyun i915_gem_object_put(obj);
5539*4882a593Smuzhiyun return ERR_PTR(err);
5540*4882a593Smuzhiyun }
5541*4882a593Smuzhiyun
5542*4882a593Smuzhiyun return vma;
5543*4882a593Smuzhiyun }
5544*4882a593Smuzhiyun
5545*4882a593Smuzhiyun static struct i915_vma *
store_context(struct intel_context * ce,struct i915_vma * scratch)5546*4882a593Smuzhiyun store_context(struct intel_context *ce, struct i915_vma *scratch)
5547*4882a593Smuzhiyun {
5548*4882a593Smuzhiyun struct i915_vma *batch;
5549*4882a593Smuzhiyun u32 dw, x, *cs, *hw;
5550*4882a593Smuzhiyun u32 *defaults;
5551*4882a593Smuzhiyun
5552*4882a593Smuzhiyun batch = create_user_vma(ce->vm, SZ_64K);
5553*4882a593Smuzhiyun if (IS_ERR(batch))
5554*4882a593Smuzhiyun return batch;
5555*4882a593Smuzhiyun
5556*4882a593Smuzhiyun cs = i915_gem_object_pin_map(batch->obj, I915_MAP_WC);
5557*4882a593Smuzhiyun if (IS_ERR(cs)) {
5558*4882a593Smuzhiyun i915_vma_put(batch);
5559*4882a593Smuzhiyun return ERR_CAST(cs);
5560*4882a593Smuzhiyun }
5561*4882a593Smuzhiyun
5562*4882a593Smuzhiyun defaults = shmem_pin_map(ce->engine->default_state);
5563*4882a593Smuzhiyun if (!defaults) {
5564*4882a593Smuzhiyun i915_gem_object_unpin_map(batch->obj);
5565*4882a593Smuzhiyun i915_vma_put(batch);
5566*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
5567*4882a593Smuzhiyun }
5568*4882a593Smuzhiyun
5569*4882a593Smuzhiyun x = 0;
5570*4882a593Smuzhiyun dw = 0;
5571*4882a593Smuzhiyun hw = defaults;
5572*4882a593Smuzhiyun hw += LRC_STATE_OFFSET / sizeof(*hw);
5573*4882a593Smuzhiyun do {
5574*4882a593Smuzhiyun u32 len = hw[dw] & 0x7f;
5575*4882a593Smuzhiyun
5576*4882a593Smuzhiyun if (hw[dw] == 0) {
5577*4882a593Smuzhiyun dw++;
5578*4882a593Smuzhiyun continue;
5579*4882a593Smuzhiyun }
5580*4882a593Smuzhiyun
5581*4882a593Smuzhiyun if ((hw[dw] & GENMASK(31, 23)) != MI_INSTR(0x22, 0)) {
5582*4882a593Smuzhiyun dw += len + 2;
5583*4882a593Smuzhiyun continue;
5584*4882a593Smuzhiyun }
5585*4882a593Smuzhiyun
5586*4882a593Smuzhiyun dw++;
5587*4882a593Smuzhiyun len = (len + 1) / 2;
5588*4882a593Smuzhiyun while (len--) {
5589*4882a593Smuzhiyun *cs++ = MI_STORE_REGISTER_MEM_GEN8;
5590*4882a593Smuzhiyun *cs++ = hw[dw];
5591*4882a593Smuzhiyun *cs++ = lower_32_bits(scratch->node.start + x);
5592*4882a593Smuzhiyun *cs++ = upper_32_bits(scratch->node.start + x);
5593*4882a593Smuzhiyun
5594*4882a593Smuzhiyun dw += 2;
5595*4882a593Smuzhiyun x += 4;
5596*4882a593Smuzhiyun }
5597*4882a593Smuzhiyun } while (dw < PAGE_SIZE / sizeof(u32) &&
5598*4882a593Smuzhiyun (hw[dw] & ~BIT(0)) != MI_BATCH_BUFFER_END);
5599*4882a593Smuzhiyun
5600*4882a593Smuzhiyun *cs++ = MI_BATCH_BUFFER_END;
5601*4882a593Smuzhiyun
5602*4882a593Smuzhiyun shmem_unpin_map(ce->engine->default_state, defaults);
5603*4882a593Smuzhiyun
5604*4882a593Smuzhiyun i915_gem_object_flush_map(batch->obj);
5605*4882a593Smuzhiyun i915_gem_object_unpin_map(batch->obj);
5606*4882a593Smuzhiyun
5607*4882a593Smuzhiyun return batch;
5608*4882a593Smuzhiyun }
5609*4882a593Smuzhiyun
move_to_active(struct i915_request * rq,struct i915_vma * vma,unsigned int flags)5610*4882a593Smuzhiyun static int move_to_active(struct i915_request *rq,
5611*4882a593Smuzhiyun struct i915_vma *vma,
5612*4882a593Smuzhiyun unsigned int flags)
5613*4882a593Smuzhiyun {
5614*4882a593Smuzhiyun int err;
5615*4882a593Smuzhiyun
5616*4882a593Smuzhiyun i915_vma_lock(vma);
5617*4882a593Smuzhiyun err = i915_request_await_object(rq, vma->obj, flags);
5618*4882a593Smuzhiyun if (!err)
5619*4882a593Smuzhiyun err = i915_vma_move_to_active(vma, rq, flags);
5620*4882a593Smuzhiyun i915_vma_unlock(vma);
5621*4882a593Smuzhiyun
5622*4882a593Smuzhiyun return err;
5623*4882a593Smuzhiyun }
5624*4882a593Smuzhiyun
5625*4882a593Smuzhiyun static struct i915_request *
record_registers(struct intel_context * ce,struct i915_vma * before,struct i915_vma * after,u32 * sema)5626*4882a593Smuzhiyun record_registers(struct intel_context *ce,
5627*4882a593Smuzhiyun struct i915_vma *before,
5628*4882a593Smuzhiyun struct i915_vma *after,
5629*4882a593Smuzhiyun u32 *sema)
5630*4882a593Smuzhiyun {
5631*4882a593Smuzhiyun struct i915_vma *b_before, *b_after;
5632*4882a593Smuzhiyun struct i915_request *rq;
5633*4882a593Smuzhiyun u32 *cs;
5634*4882a593Smuzhiyun int err;
5635*4882a593Smuzhiyun
5636*4882a593Smuzhiyun b_before = store_context(ce, before);
5637*4882a593Smuzhiyun if (IS_ERR(b_before))
5638*4882a593Smuzhiyun return ERR_CAST(b_before);
5639*4882a593Smuzhiyun
5640*4882a593Smuzhiyun b_after = store_context(ce, after);
5641*4882a593Smuzhiyun if (IS_ERR(b_after)) {
5642*4882a593Smuzhiyun rq = ERR_CAST(b_after);
5643*4882a593Smuzhiyun goto err_before;
5644*4882a593Smuzhiyun }
5645*4882a593Smuzhiyun
5646*4882a593Smuzhiyun rq = intel_context_create_request(ce);
5647*4882a593Smuzhiyun if (IS_ERR(rq))
5648*4882a593Smuzhiyun goto err_after;
5649*4882a593Smuzhiyun
5650*4882a593Smuzhiyun err = move_to_active(rq, before, EXEC_OBJECT_WRITE);
5651*4882a593Smuzhiyun if (err)
5652*4882a593Smuzhiyun goto err_rq;
5653*4882a593Smuzhiyun
5654*4882a593Smuzhiyun err = move_to_active(rq, b_before, 0);
5655*4882a593Smuzhiyun if (err)
5656*4882a593Smuzhiyun goto err_rq;
5657*4882a593Smuzhiyun
5658*4882a593Smuzhiyun err = move_to_active(rq, after, EXEC_OBJECT_WRITE);
5659*4882a593Smuzhiyun if (err)
5660*4882a593Smuzhiyun goto err_rq;
5661*4882a593Smuzhiyun
5662*4882a593Smuzhiyun err = move_to_active(rq, b_after, 0);
5663*4882a593Smuzhiyun if (err)
5664*4882a593Smuzhiyun goto err_rq;
5665*4882a593Smuzhiyun
5666*4882a593Smuzhiyun cs = intel_ring_begin(rq, 14);
5667*4882a593Smuzhiyun if (IS_ERR(cs)) {
5668*4882a593Smuzhiyun err = PTR_ERR(cs);
5669*4882a593Smuzhiyun goto err_rq;
5670*4882a593Smuzhiyun }
5671*4882a593Smuzhiyun
5672*4882a593Smuzhiyun *cs++ = MI_ARB_ON_OFF | MI_ARB_DISABLE;
5673*4882a593Smuzhiyun *cs++ = MI_BATCH_BUFFER_START_GEN8 | BIT(8);
5674*4882a593Smuzhiyun *cs++ = lower_32_bits(b_before->node.start);
5675*4882a593Smuzhiyun *cs++ = upper_32_bits(b_before->node.start);
5676*4882a593Smuzhiyun
5677*4882a593Smuzhiyun *cs++ = MI_ARB_ON_OFF | MI_ARB_ENABLE;
5678*4882a593Smuzhiyun *cs++ = MI_SEMAPHORE_WAIT |
5679*4882a593Smuzhiyun MI_SEMAPHORE_GLOBAL_GTT |
5680*4882a593Smuzhiyun MI_SEMAPHORE_POLL |
5681*4882a593Smuzhiyun MI_SEMAPHORE_SAD_NEQ_SDD;
5682*4882a593Smuzhiyun *cs++ = 0;
5683*4882a593Smuzhiyun *cs++ = i915_ggtt_offset(ce->engine->status_page.vma) +
5684*4882a593Smuzhiyun offset_in_page(sema);
5685*4882a593Smuzhiyun *cs++ = 0;
5686*4882a593Smuzhiyun *cs++ = MI_NOOP;
5687*4882a593Smuzhiyun
5688*4882a593Smuzhiyun *cs++ = MI_ARB_ON_OFF | MI_ARB_DISABLE;
5689*4882a593Smuzhiyun *cs++ = MI_BATCH_BUFFER_START_GEN8 | BIT(8);
5690*4882a593Smuzhiyun *cs++ = lower_32_bits(b_after->node.start);
5691*4882a593Smuzhiyun *cs++ = upper_32_bits(b_after->node.start);
5692*4882a593Smuzhiyun
5693*4882a593Smuzhiyun intel_ring_advance(rq, cs);
5694*4882a593Smuzhiyun
5695*4882a593Smuzhiyun WRITE_ONCE(*sema, 0);
5696*4882a593Smuzhiyun i915_request_get(rq);
5697*4882a593Smuzhiyun i915_request_add(rq);
5698*4882a593Smuzhiyun err_after:
5699*4882a593Smuzhiyun i915_vma_put(b_after);
5700*4882a593Smuzhiyun err_before:
5701*4882a593Smuzhiyun i915_vma_put(b_before);
5702*4882a593Smuzhiyun return rq;
5703*4882a593Smuzhiyun
5704*4882a593Smuzhiyun err_rq:
5705*4882a593Smuzhiyun i915_request_add(rq);
5706*4882a593Smuzhiyun rq = ERR_PTR(err);
5707*4882a593Smuzhiyun goto err_after;
5708*4882a593Smuzhiyun }
5709*4882a593Smuzhiyun
load_context(struct intel_context * ce,u32 poison)5710*4882a593Smuzhiyun static struct i915_vma *load_context(struct intel_context *ce, u32 poison)
5711*4882a593Smuzhiyun {
5712*4882a593Smuzhiyun struct i915_vma *batch;
5713*4882a593Smuzhiyun u32 dw, *cs, *hw;
5714*4882a593Smuzhiyun u32 *defaults;
5715*4882a593Smuzhiyun
5716*4882a593Smuzhiyun batch = create_user_vma(ce->vm, SZ_64K);
5717*4882a593Smuzhiyun if (IS_ERR(batch))
5718*4882a593Smuzhiyun return batch;
5719*4882a593Smuzhiyun
5720*4882a593Smuzhiyun cs = i915_gem_object_pin_map(batch->obj, I915_MAP_WC);
5721*4882a593Smuzhiyun if (IS_ERR(cs)) {
5722*4882a593Smuzhiyun i915_vma_put(batch);
5723*4882a593Smuzhiyun return ERR_CAST(cs);
5724*4882a593Smuzhiyun }
5725*4882a593Smuzhiyun
5726*4882a593Smuzhiyun defaults = shmem_pin_map(ce->engine->default_state);
5727*4882a593Smuzhiyun if (!defaults) {
5728*4882a593Smuzhiyun i915_gem_object_unpin_map(batch->obj);
5729*4882a593Smuzhiyun i915_vma_put(batch);
5730*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
5731*4882a593Smuzhiyun }
5732*4882a593Smuzhiyun
5733*4882a593Smuzhiyun dw = 0;
5734*4882a593Smuzhiyun hw = defaults;
5735*4882a593Smuzhiyun hw += LRC_STATE_OFFSET / sizeof(*hw);
5736*4882a593Smuzhiyun do {
5737*4882a593Smuzhiyun u32 len = hw[dw] & 0x7f;
5738*4882a593Smuzhiyun
5739*4882a593Smuzhiyun if (hw[dw] == 0) {
5740*4882a593Smuzhiyun dw++;
5741*4882a593Smuzhiyun continue;
5742*4882a593Smuzhiyun }
5743*4882a593Smuzhiyun
5744*4882a593Smuzhiyun if ((hw[dw] & GENMASK(31, 23)) != MI_INSTR(0x22, 0)) {
5745*4882a593Smuzhiyun dw += len + 2;
5746*4882a593Smuzhiyun continue;
5747*4882a593Smuzhiyun }
5748*4882a593Smuzhiyun
5749*4882a593Smuzhiyun dw++;
5750*4882a593Smuzhiyun len = (len + 1) / 2;
5751*4882a593Smuzhiyun *cs++ = MI_LOAD_REGISTER_IMM(len);
5752*4882a593Smuzhiyun while (len--) {
5753*4882a593Smuzhiyun *cs++ = hw[dw];
5754*4882a593Smuzhiyun *cs++ = poison;
5755*4882a593Smuzhiyun dw += 2;
5756*4882a593Smuzhiyun }
5757*4882a593Smuzhiyun } while (dw < PAGE_SIZE / sizeof(u32) &&
5758*4882a593Smuzhiyun (hw[dw] & ~BIT(0)) != MI_BATCH_BUFFER_END);
5759*4882a593Smuzhiyun
5760*4882a593Smuzhiyun *cs++ = MI_BATCH_BUFFER_END;
5761*4882a593Smuzhiyun
5762*4882a593Smuzhiyun shmem_unpin_map(ce->engine->default_state, defaults);
5763*4882a593Smuzhiyun
5764*4882a593Smuzhiyun i915_gem_object_flush_map(batch->obj);
5765*4882a593Smuzhiyun i915_gem_object_unpin_map(batch->obj);
5766*4882a593Smuzhiyun
5767*4882a593Smuzhiyun return batch;
5768*4882a593Smuzhiyun }
5769*4882a593Smuzhiyun
poison_registers(struct intel_context * ce,u32 poison,u32 * sema)5770*4882a593Smuzhiyun static int poison_registers(struct intel_context *ce, u32 poison, u32 *sema)
5771*4882a593Smuzhiyun {
5772*4882a593Smuzhiyun struct i915_request *rq;
5773*4882a593Smuzhiyun struct i915_vma *batch;
5774*4882a593Smuzhiyun u32 *cs;
5775*4882a593Smuzhiyun int err;
5776*4882a593Smuzhiyun
5777*4882a593Smuzhiyun batch = load_context(ce, poison);
5778*4882a593Smuzhiyun if (IS_ERR(batch))
5779*4882a593Smuzhiyun return PTR_ERR(batch);
5780*4882a593Smuzhiyun
5781*4882a593Smuzhiyun rq = intel_context_create_request(ce);
5782*4882a593Smuzhiyun if (IS_ERR(rq)) {
5783*4882a593Smuzhiyun err = PTR_ERR(rq);
5784*4882a593Smuzhiyun goto err_batch;
5785*4882a593Smuzhiyun }
5786*4882a593Smuzhiyun
5787*4882a593Smuzhiyun err = move_to_active(rq, batch, 0);
5788*4882a593Smuzhiyun if (err)
5789*4882a593Smuzhiyun goto err_rq;
5790*4882a593Smuzhiyun
5791*4882a593Smuzhiyun cs = intel_ring_begin(rq, 8);
5792*4882a593Smuzhiyun if (IS_ERR(cs)) {
5793*4882a593Smuzhiyun err = PTR_ERR(cs);
5794*4882a593Smuzhiyun goto err_rq;
5795*4882a593Smuzhiyun }
5796*4882a593Smuzhiyun
5797*4882a593Smuzhiyun *cs++ = MI_ARB_ON_OFF | MI_ARB_DISABLE;
5798*4882a593Smuzhiyun *cs++ = MI_BATCH_BUFFER_START_GEN8 | BIT(8);
5799*4882a593Smuzhiyun *cs++ = lower_32_bits(batch->node.start);
5800*4882a593Smuzhiyun *cs++ = upper_32_bits(batch->node.start);
5801*4882a593Smuzhiyun
5802*4882a593Smuzhiyun *cs++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
5803*4882a593Smuzhiyun *cs++ = i915_ggtt_offset(ce->engine->status_page.vma) +
5804*4882a593Smuzhiyun offset_in_page(sema);
5805*4882a593Smuzhiyun *cs++ = 0;
5806*4882a593Smuzhiyun *cs++ = 1;
5807*4882a593Smuzhiyun
5808*4882a593Smuzhiyun intel_ring_advance(rq, cs);
5809*4882a593Smuzhiyun
5810*4882a593Smuzhiyun rq->sched.attr.priority = I915_PRIORITY_BARRIER;
5811*4882a593Smuzhiyun err_rq:
5812*4882a593Smuzhiyun i915_request_add(rq);
5813*4882a593Smuzhiyun err_batch:
5814*4882a593Smuzhiyun i915_vma_put(batch);
5815*4882a593Smuzhiyun return err;
5816*4882a593Smuzhiyun }
5817*4882a593Smuzhiyun
is_moving(u32 a,u32 b)5818*4882a593Smuzhiyun static bool is_moving(u32 a, u32 b)
5819*4882a593Smuzhiyun {
5820*4882a593Smuzhiyun return a != b;
5821*4882a593Smuzhiyun }
5822*4882a593Smuzhiyun
compare_isolation(struct intel_engine_cs * engine,struct i915_vma * ref[2],struct i915_vma * result[2],struct intel_context * ce,u32 poison)5823*4882a593Smuzhiyun static int compare_isolation(struct intel_engine_cs *engine,
5824*4882a593Smuzhiyun struct i915_vma *ref[2],
5825*4882a593Smuzhiyun struct i915_vma *result[2],
5826*4882a593Smuzhiyun struct intel_context *ce,
5827*4882a593Smuzhiyun u32 poison)
5828*4882a593Smuzhiyun {
5829*4882a593Smuzhiyun u32 x, dw, *hw, *lrc;
5830*4882a593Smuzhiyun u32 *A[2], *B[2];
5831*4882a593Smuzhiyun u32 *defaults;
5832*4882a593Smuzhiyun int err = 0;
5833*4882a593Smuzhiyun
5834*4882a593Smuzhiyun A[0] = i915_gem_object_pin_map(ref[0]->obj, I915_MAP_WC);
5835*4882a593Smuzhiyun if (IS_ERR(A[0]))
5836*4882a593Smuzhiyun return PTR_ERR(A[0]);
5837*4882a593Smuzhiyun
5838*4882a593Smuzhiyun A[1] = i915_gem_object_pin_map(ref[1]->obj, I915_MAP_WC);
5839*4882a593Smuzhiyun if (IS_ERR(A[1])) {
5840*4882a593Smuzhiyun err = PTR_ERR(A[1]);
5841*4882a593Smuzhiyun goto err_A0;
5842*4882a593Smuzhiyun }
5843*4882a593Smuzhiyun
5844*4882a593Smuzhiyun B[0] = i915_gem_object_pin_map(result[0]->obj, I915_MAP_WC);
5845*4882a593Smuzhiyun if (IS_ERR(B[0])) {
5846*4882a593Smuzhiyun err = PTR_ERR(B[0]);
5847*4882a593Smuzhiyun goto err_A1;
5848*4882a593Smuzhiyun }
5849*4882a593Smuzhiyun
5850*4882a593Smuzhiyun B[1] = i915_gem_object_pin_map(result[1]->obj, I915_MAP_WC);
5851*4882a593Smuzhiyun if (IS_ERR(B[1])) {
5852*4882a593Smuzhiyun err = PTR_ERR(B[1]);
5853*4882a593Smuzhiyun goto err_B0;
5854*4882a593Smuzhiyun }
5855*4882a593Smuzhiyun
5856*4882a593Smuzhiyun lrc = i915_gem_object_pin_map(ce->state->obj,
5857*4882a593Smuzhiyun i915_coherent_map_type(engine->i915));
5858*4882a593Smuzhiyun if (IS_ERR(lrc)) {
5859*4882a593Smuzhiyun err = PTR_ERR(lrc);
5860*4882a593Smuzhiyun goto err_B1;
5861*4882a593Smuzhiyun }
5862*4882a593Smuzhiyun lrc += LRC_STATE_OFFSET / sizeof(*hw);
5863*4882a593Smuzhiyun
5864*4882a593Smuzhiyun defaults = shmem_pin_map(ce->engine->default_state);
5865*4882a593Smuzhiyun if (!defaults) {
5866*4882a593Smuzhiyun err = -ENOMEM;
5867*4882a593Smuzhiyun goto err_lrc;
5868*4882a593Smuzhiyun }
5869*4882a593Smuzhiyun
5870*4882a593Smuzhiyun x = 0;
5871*4882a593Smuzhiyun dw = 0;
5872*4882a593Smuzhiyun hw = defaults;
5873*4882a593Smuzhiyun hw += LRC_STATE_OFFSET / sizeof(*hw);
5874*4882a593Smuzhiyun do {
5875*4882a593Smuzhiyun u32 len = hw[dw] & 0x7f;
5876*4882a593Smuzhiyun
5877*4882a593Smuzhiyun if (hw[dw] == 0) {
5878*4882a593Smuzhiyun dw++;
5879*4882a593Smuzhiyun continue;
5880*4882a593Smuzhiyun }
5881*4882a593Smuzhiyun
5882*4882a593Smuzhiyun if ((hw[dw] & GENMASK(31, 23)) != MI_INSTR(0x22, 0)) {
5883*4882a593Smuzhiyun dw += len + 2;
5884*4882a593Smuzhiyun continue;
5885*4882a593Smuzhiyun }
5886*4882a593Smuzhiyun
5887*4882a593Smuzhiyun dw++;
5888*4882a593Smuzhiyun len = (len + 1) / 2;
5889*4882a593Smuzhiyun while (len--) {
5890*4882a593Smuzhiyun if (!is_moving(A[0][x], A[1][x]) &&
5891*4882a593Smuzhiyun (A[0][x] != B[0][x] || A[1][x] != B[1][x])) {
5892*4882a593Smuzhiyun switch (hw[dw] & 4095) {
5893*4882a593Smuzhiyun case 0x30: /* RING_HEAD */
5894*4882a593Smuzhiyun case 0x34: /* RING_TAIL */
5895*4882a593Smuzhiyun break;
5896*4882a593Smuzhiyun
5897*4882a593Smuzhiyun default:
5898*4882a593Smuzhiyun pr_err("%s[%d]: Mismatch for register %4x, default %08x, reference %08x, result (%08x, %08x), poison %08x, context %08x\n",
5899*4882a593Smuzhiyun engine->name, dw,
5900*4882a593Smuzhiyun hw[dw], hw[dw + 1],
5901*4882a593Smuzhiyun A[0][x], B[0][x], B[1][x],
5902*4882a593Smuzhiyun poison, lrc[dw + 1]);
5903*4882a593Smuzhiyun err = -EINVAL;
5904*4882a593Smuzhiyun }
5905*4882a593Smuzhiyun }
5906*4882a593Smuzhiyun dw += 2;
5907*4882a593Smuzhiyun x++;
5908*4882a593Smuzhiyun }
5909*4882a593Smuzhiyun } while (dw < PAGE_SIZE / sizeof(u32) &&
5910*4882a593Smuzhiyun (hw[dw] & ~BIT(0)) != MI_BATCH_BUFFER_END);
5911*4882a593Smuzhiyun
5912*4882a593Smuzhiyun shmem_unpin_map(ce->engine->default_state, defaults);
5913*4882a593Smuzhiyun err_lrc:
5914*4882a593Smuzhiyun i915_gem_object_unpin_map(ce->state->obj);
5915*4882a593Smuzhiyun err_B1:
5916*4882a593Smuzhiyun i915_gem_object_unpin_map(result[1]->obj);
5917*4882a593Smuzhiyun err_B0:
5918*4882a593Smuzhiyun i915_gem_object_unpin_map(result[0]->obj);
5919*4882a593Smuzhiyun err_A1:
5920*4882a593Smuzhiyun i915_gem_object_unpin_map(ref[1]->obj);
5921*4882a593Smuzhiyun err_A0:
5922*4882a593Smuzhiyun i915_gem_object_unpin_map(ref[0]->obj);
5923*4882a593Smuzhiyun return err;
5924*4882a593Smuzhiyun }
5925*4882a593Smuzhiyun
__lrc_isolation(struct intel_engine_cs * engine,u32 poison)5926*4882a593Smuzhiyun static int __lrc_isolation(struct intel_engine_cs *engine, u32 poison)
5927*4882a593Smuzhiyun {
5928*4882a593Smuzhiyun u32 *sema = memset32(engine->status_page.addr + 1000, 0, 1);
5929*4882a593Smuzhiyun struct i915_vma *ref[2], *result[2];
5930*4882a593Smuzhiyun struct intel_context *A, *B;
5931*4882a593Smuzhiyun struct i915_request *rq;
5932*4882a593Smuzhiyun int err;
5933*4882a593Smuzhiyun
5934*4882a593Smuzhiyun A = intel_context_create(engine);
5935*4882a593Smuzhiyun if (IS_ERR(A))
5936*4882a593Smuzhiyun return PTR_ERR(A);
5937*4882a593Smuzhiyun
5938*4882a593Smuzhiyun B = intel_context_create(engine);
5939*4882a593Smuzhiyun if (IS_ERR(B)) {
5940*4882a593Smuzhiyun err = PTR_ERR(B);
5941*4882a593Smuzhiyun goto err_A;
5942*4882a593Smuzhiyun }
5943*4882a593Smuzhiyun
5944*4882a593Smuzhiyun ref[0] = create_user_vma(A->vm, SZ_64K);
5945*4882a593Smuzhiyun if (IS_ERR(ref[0])) {
5946*4882a593Smuzhiyun err = PTR_ERR(ref[0]);
5947*4882a593Smuzhiyun goto err_B;
5948*4882a593Smuzhiyun }
5949*4882a593Smuzhiyun
5950*4882a593Smuzhiyun ref[1] = create_user_vma(A->vm, SZ_64K);
5951*4882a593Smuzhiyun if (IS_ERR(ref[1])) {
5952*4882a593Smuzhiyun err = PTR_ERR(ref[1]);
5953*4882a593Smuzhiyun goto err_ref0;
5954*4882a593Smuzhiyun }
5955*4882a593Smuzhiyun
5956*4882a593Smuzhiyun rq = record_registers(A, ref[0], ref[1], sema);
5957*4882a593Smuzhiyun if (IS_ERR(rq)) {
5958*4882a593Smuzhiyun err = PTR_ERR(rq);
5959*4882a593Smuzhiyun goto err_ref1;
5960*4882a593Smuzhiyun }
5961*4882a593Smuzhiyun
5962*4882a593Smuzhiyun WRITE_ONCE(*sema, 1);
5963*4882a593Smuzhiyun wmb();
5964*4882a593Smuzhiyun
5965*4882a593Smuzhiyun if (i915_request_wait(rq, 0, HZ / 2) < 0) {
5966*4882a593Smuzhiyun i915_request_put(rq);
5967*4882a593Smuzhiyun err = -ETIME;
5968*4882a593Smuzhiyun goto err_ref1;
5969*4882a593Smuzhiyun }
5970*4882a593Smuzhiyun i915_request_put(rq);
5971*4882a593Smuzhiyun
5972*4882a593Smuzhiyun result[0] = create_user_vma(A->vm, SZ_64K);
5973*4882a593Smuzhiyun if (IS_ERR(result[0])) {
5974*4882a593Smuzhiyun err = PTR_ERR(result[0]);
5975*4882a593Smuzhiyun goto err_ref1;
5976*4882a593Smuzhiyun }
5977*4882a593Smuzhiyun
5978*4882a593Smuzhiyun result[1] = create_user_vma(A->vm, SZ_64K);
5979*4882a593Smuzhiyun if (IS_ERR(result[1])) {
5980*4882a593Smuzhiyun err = PTR_ERR(result[1]);
5981*4882a593Smuzhiyun goto err_result0;
5982*4882a593Smuzhiyun }
5983*4882a593Smuzhiyun
5984*4882a593Smuzhiyun rq = record_registers(A, result[0], result[1], sema);
5985*4882a593Smuzhiyun if (IS_ERR(rq)) {
5986*4882a593Smuzhiyun err = PTR_ERR(rq);
5987*4882a593Smuzhiyun goto err_result1;
5988*4882a593Smuzhiyun }
5989*4882a593Smuzhiyun
5990*4882a593Smuzhiyun err = poison_registers(B, poison, sema);
5991*4882a593Smuzhiyun if (err) {
5992*4882a593Smuzhiyun WRITE_ONCE(*sema, -1);
5993*4882a593Smuzhiyun i915_request_put(rq);
5994*4882a593Smuzhiyun goto err_result1;
5995*4882a593Smuzhiyun }
5996*4882a593Smuzhiyun
5997*4882a593Smuzhiyun if (i915_request_wait(rq, 0, HZ / 2) < 0) {
5998*4882a593Smuzhiyun i915_request_put(rq);
5999*4882a593Smuzhiyun err = -ETIME;
6000*4882a593Smuzhiyun goto err_result1;
6001*4882a593Smuzhiyun }
6002*4882a593Smuzhiyun i915_request_put(rq);
6003*4882a593Smuzhiyun
6004*4882a593Smuzhiyun err = compare_isolation(engine, ref, result, A, poison);
6005*4882a593Smuzhiyun
6006*4882a593Smuzhiyun err_result1:
6007*4882a593Smuzhiyun i915_vma_put(result[1]);
6008*4882a593Smuzhiyun err_result0:
6009*4882a593Smuzhiyun i915_vma_put(result[0]);
6010*4882a593Smuzhiyun err_ref1:
6011*4882a593Smuzhiyun i915_vma_put(ref[1]);
6012*4882a593Smuzhiyun err_ref0:
6013*4882a593Smuzhiyun i915_vma_put(ref[0]);
6014*4882a593Smuzhiyun err_B:
6015*4882a593Smuzhiyun intel_context_put(B);
6016*4882a593Smuzhiyun err_A:
6017*4882a593Smuzhiyun intel_context_put(A);
6018*4882a593Smuzhiyun return err;
6019*4882a593Smuzhiyun }
6020*4882a593Smuzhiyun
skip_isolation(const struct intel_engine_cs * engine)6021*4882a593Smuzhiyun static bool skip_isolation(const struct intel_engine_cs *engine)
6022*4882a593Smuzhiyun {
6023*4882a593Smuzhiyun if (engine->class == COPY_ENGINE_CLASS && INTEL_GEN(engine->i915) == 9)
6024*4882a593Smuzhiyun return true;
6025*4882a593Smuzhiyun
6026*4882a593Smuzhiyun if (engine->class == RENDER_CLASS && INTEL_GEN(engine->i915) == 11)
6027*4882a593Smuzhiyun return true;
6028*4882a593Smuzhiyun
6029*4882a593Smuzhiyun return false;
6030*4882a593Smuzhiyun }
6031*4882a593Smuzhiyun
live_lrc_isolation(void * arg)6032*4882a593Smuzhiyun static int live_lrc_isolation(void *arg)
6033*4882a593Smuzhiyun {
6034*4882a593Smuzhiyun struct intel_gt *gt = arg;
6035*4882a593Smuzhiyun struct intel_engine_cs *engine;
6036*4882a593Smuzhiyun enum intel_engine_id id;
6037*4882a593Smuzhiyun const u32 poison[] = {
6038*4882a593Smuzhiyun STACK_MAGIC,
6039*4882a593Smuzhiyun 0x3a3a3a3a,
6040*4882a593Smuzhiyun 0x5c5c5c5c,
6041*4882a593Smuzhiyun 0xffffffff,
6042*4882a593Smuzhiyun 0xffff0000,
6043*4882a593Smuzhiyun };
6044*4882a593Smuzhiyun int err = 0;
6045*4882a593Smuzhiyun
6046*4882a593Smuzhiyun /*
6047*4882a593Smuzhiyun * Our goal is try and verify that per-context state cannot be
6048*4882a593Smuzhiyun * tampered with by another non-privileged client.
6049*4882a593Smuzhiyun *
6050*4882a593Smuzhiyun * We take the list of context registers from the LRI in the default
6051*4882a593Smuzhiyun * context image and attempt to modify that list from a remote context.
6052*4882a593Smuzhiyun */
6053*4882a593Smuzhiyun
6054*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
6055*4882a593Smuzhiyun int i;
6056*4882a593Smuzhiyun
6057*4882a593Smuzhiyun /* Just don't even ask */
6058*4882a593Smuzhiyun if (!IS_ENABLED(CONFIG_DRM_I915_SELFTEST_BROKEN) &&
6059*4882a593Smuzhiyun skip_isolation(engine))
6060*4882a593Smuzhiyun continue;
6061*4882a593Smuzhiyun
6062*4882a593Smuzhiyun intel_engine_pm_get(engine);
6063*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(poison); i++) {
6064*4882a593Smuzhiyun int result;
6065*4882a593Smuzhiyun
6066*4882a593Smuzhiyun result = __lrc_isolation(engine, poison[i]);
6067*4882a593Smuzhiyun if (result && !err)
6068*4882a593Smuzhiyun err = result;
6069*4882a593Smuzhiyun
6070*4882a593Smuzhiyun result = __lrc_isolation(engine, ~poison[i]);
6071*4882a593Smuzhiyun if (result && !err)
6072*4882a593Smuzhiyun err = result;
6073*4882a593Smuzhiyun }
6074*4882a593Smuzhiyun intel_engine_pm_put(engine);
6075*4882a593Smuzhiyun if (igt_flush_test(gt->i915)) {
6076*4882a593Smuzhiyun err = -EIO;
6077*4882a593Smuzhiyun break;
6078*4882a593Smuzhiyun }
6079*4882a593Smuzhiyun }
6080*4882a593Smuzhiyun
6081*4882a593Smuzhiyun return err;
6082*4882a593Smuzhiyun }
6083*4882a593Smuzhiyun
indirect_ctx_submit_req(struct intel_context * ce)6084*4882a593Smuzhiyun static int indirect_ctx_submit_req(struct intel_context *ce)
6085*4882a593Smuzhiyun {
6086*4882a593Smuzhiyun struct i915_request *rq;
6087*4882a593Smuzhiyun int err = 0;
6088*4882a593Smuzhiyun
6089*4882a593Smuzhiyun rq = intel_context_create_request(ce);
6090*4882a593Smuzhiyun if (IS_ERR(rq))
6091*4882a593Smuzhiyun return PTR_ERR(rq);
6092*4882a593Smuzhiyun
6093*4882a593Smuzhiyun i915_request_get(rq);
6094*4882a593Smuzhiyun i915_request_add(rq);
6095*4882a593Smuzhiyun
6096*4882a593Smuzhiyun if (i915_request_wait(rq, 0, HZ / 5) < 0)
6097*4882a593Smuzhiyun err = -ETIME;
6098*4882a593Smuzhiyun
6099*4882a593Smuzhiyun i915_request_put(rq);
6100*4882a593Smuzhiyun
6101*4882a593Smuzhiyun return err;
6102*4882a593Smuzhiyun }
6103*4882a593Smuzhiyun
6104*4882a593Smuzhiyun #define CTX_BB_CANARY_OFFSET (3 * 1024)
6105*4882a593Smuzhiyun #define CTX_BB_CANARY_INDEX (CTX_BB_CANARY_OFFSET / sizeof(u32))
6106*4882a593Smuzhiyun
6107*4882a593Smuzhiyun static u32 *
emit_indirect_ctx_bb_canary(const struct intel_context * ce,u32 * cs)6108*4882a593Smuzhiyun emit_indirect_ctx_bb_canary(const struct intel_context *ce, u32 *cs)
6109*4882a593Smuzhiyun {
6110*4882a593Smuzhiyun *cs++ = MI_STORE_REGISTER_MEM_GEN8 |
6111*4882a593Smuzhiyun MI_SRM_LRM_GLOBAL_GTT |
6112*4882a593Smuzhiyun MI_LRI_LRM_CS_MMIO;
6113*4882a593Smuzhiyun *cs++ = i915_mmio_reg_offset(RING_START(0));
6114*4882a593Smuzhiyun *cs++ = i915_ggtt_offset(ce->state) +
6115*4882a593Smuzhiyun context_wa_bb_offset(ce) +
6116*4882a593Smuzhiyun CTX_BB_CANARY_OFFSET;
6117*4882a593Smuzhiyun *cs++ = 0;
6118*4882a593Smuzhiyun
6119*4882a593Smuzhiyun return cs;
6120*4882a593Smuzhiyun }
6121*4882a593Smuzhiyun
6122*4882a593Smuzhiyun static void
indirect_ctx_bb_setup(struct intel_context * ce)6123*4882a593Smuzhiyun indirect_ctx_bb_setup(struct intel_context *ce)
6124*4882a593Smuzhiyun {
6125*4882a593Smuzhiyun u32 *cs = context_indirect_bb(ce);
6126*4882a593Smuzhiyun
6127*4882a593Smuzhiyun cs[CTX_BB_CANARY_INDEX] = 0xdeadf00d;
6128*4882a593Smuzhiyun
6129*4882a593Smuzhiyun setup_indirect_ctx_bb(ce, ce->engine, emit_indirect_ctx_bb_canary);
6130*4882a593Smuzhiyun }
6131*4882a593Smuzhiyun
check_ring_start(struct intel_context * ce)6132*4882a593Smuzhiyun static bool check_ring_start(struct intel_context *ce)
6133*4882a593Smuzhiyun {
6134*4882a593Smuzhiyun const u32 * const ctx_bb = (void *)(ce->lrc_reg_state) -
6135*4882a593Smuzhiyun LRC_STATE_OFFSET + context_wa_bb_offset(ce);
6136*4882a593Smuzhiyun
6137*4882a593Smuzhiyun if (ctx_bb[CTX_BB_CANARY_INDEX] == ce->lrc_reg_state[CTX_RING_START])
6138*4882a593Smuzhiyun return true;
6139*4882a593Smuzhiyun
6140*4882a593Smuzhiyun pr_err("ring start mismatch: canary 0x%08x vs state 0x%08x\n",
6141*4882a593Smuzhiyun ctx_bb[CTX_BB_CANARY_INDEX],
6142*4882a593Smuzhiyun ce->lrc_reg_state[CTX_RING_START]);
6143*4882a593Smuzhiyun
6144*4882a593Smuzhiyun return false;
6145*4882a593Smuzhiyun }
6146*4882a593Smuzhiyun
indirect_ctx_bb_check(struct intel_context * ce)6147*4882a593Smuzhiyun static int indirect_ctx_bb_check(struct intel_context *ce)
6148*4882a593Smuzhiyun {
6149*4882a593Smuzhiyun int err;
6150*4882a593Smuzhiyun
6151*4882a593Smuzhiyun err = indirect_ctx_submit_req(ce);
6152*4882a593Smuzhiyun if (err)
6153*4882a593Smuzhiyun return err;
6154*4882a593Smuzhiyun
6155*4882a593Smuzhiyun if (!check_ring_start(ce))
6156*4882a593Smuzhiyun return -EINVAL;
6157*4882a593Smuzhiyun
6158*4882a593Smuzhiyun return 0;
6159*4882a593Smuzhiyun }
6160*4882a593Smuzhiyun
__live_lrc_indirect_ctx_bb(struct intel_engine_cs * engine)6161*4882a593Smuzhiyun static int __live_lrc_indirect_ctx_bb(struct intel_engine_cs *engine)
6162*4882a593Smuzhiyun {
6163*4882a593Smuzhiyun struct intel_context *a, *b;
6164*4882a593Smuzhiyun int err;
6165*4882a593Smuzhiyun
6166*4882a593Smuzhiyun a = intel_context_create(engine);
6167*4882a593Smuzhiyun if (IS_ERR(a))
6168*4882a593Smuzhiyun return PTR_ERR(a);
6169*4882a593Smuzhiyun err = intel_context_pin(a);
6170*4882a593Smuzhiyun if (err)
6171*4882a593Smuzhiyun goto put_a;
6172*4882a593Smuzhiyun
6173*4882a593Smuzhiyun b = intel_context_create(engine);
6174*4882a593Smuzhiyun if (IS_ERR(b)) {
6175*4882a593Smuzhiyun err = PTR_ERR(b);
6176*4882a593Smuzhiyun goto unpin_a;
6177*4882a593Smuzhiyun }
6178*4882a593Smuzhiyun err = intel_context_pin(b);
6179*4882a593Smuzhiyun if (err)
6180*4882a593Smuzhiyun goto put_b;
6181*4882a593Smuzhiyun
6182*4882a593Smuzhiyun /* We use the already reserved extra page in context state */
6183*4882a593Smuzhiyun if (!a->wa_bb_page) {
6184*4882a593Smuzhiyun GEM_BUG_ON(b->wa_bb_page);
6185*4882a593Smuzhiyun GEM_BUG_ON(INTEL_GEN(engine->i915) == 12);
6186*4882a593Smuzhiyun goto unpin_b;
6187*4882a593Smuzhiyun }
6188*4882a593Smuzhiyun
6189*4882a593Smuzhiyun /*
6190*4882a593Smuzhiyun * In order to test that our per context bb is truly per context,
6191*4882a593Smuzhiyun * and executes at the intended spot on context restoring process,
6192*4882a593Smuzhiyun * make the batch store the ring start value to memory.
6193*4882a593Smuzhiyun * As ring start is restored apriori of starting the indirect ctx bb and
6194*4882a593Smuzhiyun * as it will be different for each context, it fits to this purpose.
6195*4882a593Smuzhiyun */
6196*4882a593Smuzhiyun indirect_ctx_bb_setup(a);
6197*4882a593Smuzhiyun indirect_ctx_bb_setup(b);
6198*4882a593Smuzhiyun
6199*4882a593Smuzhiyun err = indirect_ctx_bb_check(a);
6200*4882a593Smuzhiyun if (err)
6201*4882a593Smuzhiyun goto unpin_b;
6202*4882a593Smuzhiyun
6203*4882a593Smuzhiyun err = indirect_ctx_bb_check(b);
6204*4882a593Smuzhiyun
6205*4882a593Smuzhiyun unpin_b:
6206*4882a593Smuzhiyun intel_context_unpin(b);
6207*4882a593Smuzhiyun put_b:
6208*4882a593Smuzhiyun intel_context_put(b);
6209*4882a593Smuzhiyun unpin_a:
6210*4882a593Smuzhiyun intel_context_unpin(a);
6211*4882a593Smuzhiyun put_a:
6212*4882a593Smuzhiyun intel_context_put(a);
6213*4882a593Smuzhiyun
6214*4882a593Smuzhiyun return err;
6215*4882a593Smuzhiyun }
6216*4882a593Smuzhiyun
live_lrc_indirect_ctx_bb(void * arg)6217*4882a593Smuzhiyun static int live_lrc_indirect_ctx_bb(void *arg)
6218*4882a593Smuzhiyun {
6219*4882a593Smuzhiyun struct intel_gt *gt = arg;
6220*4882a593Smuzhiyun struct intel_engine_cs *engine;
6221*4882a593Smuzhiyun enum intel_engine_id id;
6222*4882a593Smuzhiyun int err = 0;
6223*4882a593Smuzhiyun
6224*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
6225*4882a593Smuzhiyun intel_engine_pm_get(engine);
6226*4882a593Smuzhiyun err = __live_lrc_indirect_ctx_bb(engine);
6227*4882a593Smuzhiyun intel_engine_pm_put(engine);
6228*4882a593Smuzhiyun
6229*4882a593Smuzhiyun if (igt_flush_test(gt->i915))
6230*4882a593Smuzhiyun err = -EIO;
6231*4882a593Smuzhiyun
6232*4882a593Smuzhiyun if (err)
6233*4882a593Smuzhiyun break;
6234*4882a593Smuzhiyun }
6235*4882a593Smuzhiyun
6236*4882a593Smuzhiyun return err;
6237*4882a593Smuzhiyun }
6238*4882a593Smuzhiyun
garbage_reset(struct intel_engine_cs * engine,struct i915_request * rq)6239*4882a593Smuzhiyun static void garbage_reset(struct intel_engine_cs *engine,
6240*4882a593Smuzhiyun struct i915_request *rq)
6241*4882a593Smuzhiyun {
6242*4882a593Smuzhiyun const unsigned int bit = I915_RESET_ENGINE + engine->id;
6243*4882a593Smuzhiyun unsigned long *lock = &engine->gt->reset.flags;
6244*4882a593Smuzhiyun
6245*4882a593Smuzhiyun if (test_and_set_bit(bit, lock))
6246*4882a593Smuzhiyun return;
6247*4882a593Smuzhiyun
6248*4882a593Smuzhiyun tasklet_disable(&engine->execlists.tasklet);
6249*4882a593Smuzhiyun
6250*4882a593Smuzhiyun if (!rq->fence.error)
6251*4882a593Smuzhiyun intel_engine_reset(engine, NULL);
6252*4882a593Smuzhiyun
6253*4882a593Smuzhiyun tasklet_enable(&engine->execlists.tasklet);
6254*4882a593Smuzhiyun clear_and_wake_up_bit(bit, lock);
6255*4882a593Smuzhiyun }
6256*4882a593Smuzhiyun
garbage(struct intel_context * ce,struct rnd_state * prng)6257*4882a593Smuzhiyun static struct i915_request *garbage(struct intel_context *ce,
6258*4882a593Smuzhiyun struct rnd_state *prng)
6259*4882a593Smuzhiyun {
6260*4882a593Smuzhiyun struct i915_request *rq;
6261*4882a593Smuzhiyun int err;
6262*4882a593Smuzhiyun
6263*4882a593Smuzhiyun err = intel_context_pin(ce);
6264*4882a593Smuzhiyun if (err)
6265*4882a593Smuzhiyun return ERR_PTR(err);
6266*4882a593Smuzhiyun
6267*4882a593Smuzhiyun prandom_bytes_state(prng,
6268*4882a593Smuzhiyun ce->lrc_reg_state,
6269*4882a593Smuzhiyun ce->engine->context_size -
6270*4882a593Smuzhiyun LRC_STATE_OFFSET);
6271*4882a593Smuzhiyun
6272*4882a593Smuzhiyun rq = intel_context_create_request(ce);
6273*4882a593Smuzhiyun if (IS_ERR(rq)) {
6274*4882a593Smuzhiyun err = PTR_ERR(rq);
6275*4882a593Smuzhiyun goto err_unpin;
6276*4882a593Smuzhiyun }
6277*4882a593Smuzhiyun
6278*4882a593Smuzhiyun i915_request_get(rq);
6279*4882a593Smuzhiyun i915_request_add(rq);
6280*4882a593Smuzhiyun return rq;
6281*4882a593Smuzhiyun
6282*4882a593Smuzhiyun err_unpin:
6283*4882a593Smuzhiyun intel_context_unpin(ce);
6284*4882a593Smuzhiyun return ERR_PTR(err);
6285*4882a593Smuzhiyun }
6286*4882a593Smuzhiyun
__lrc_garbage(struct intel_engine_cs * engine,struct rnd_state * prng)6287*4882a593Smuzhiyun static int __lrc_garbage(struct intel_engine_cs *engine, struct rnd_state *prng)
6288*4882a593Smuzhiyun {
6289*4882a593Smuzhiyun struct intel_context *ce;
6290*4882a593Smuzhiyun struct i915_request *hang;
6291*4882a593Smuzhiyun int err = 0;
6292*4882a593Smuzhiyun
6293*4882a593Smuzhiyun ce = intel_context_create(engine);
6294*4882a593Smuzhiyun if (IS_ERR(ce))
6295*4882a593Smuzhiyun return PTR_ERR(ce);
6296*4882a593Smuzhiyun
6297*4882a593Smuzhiyun hang = garbage(ce, prng);
6298*4882a593Smuzhiyun if (IS_ERR(hang)) {
6299*4882a593Smuzhiyun err = PTR_ERR(hang);
6300*4882a593Smuzhiyun goto err_ce;
6301*4882a593Smuzhiyun }
6302*4882a593Smuzhiyun
6303*4882a593Smuzhiyun if (wait_for_submit(engine, hang, HZ / 2)) {
6304*4882a593Smuzhiyun i915_request_put(hang);
6305*4882a593Smuzhiyun err = -ETIME;
6306*4882a593Smuzhiyun goto err_ce;
6307*4882a593Smuzhiyun }
6308*4882a593Smuzhiyun
6309*4882a593Smuzhiyun intel_context_set_banned(ce);
6310*4882a593Smuzhiyun garbage_reset(engine, hang);
6311*4882a593Smuzhiyun
6312*4882a593Smuzhiyun intel_engine_flush_submission(engine);
6313*4882a593Smuzhiyun if (!hang->fence.error) {
6314*4882a593Smuzhiyun i915_request_put(hang);
6315*4882a593Smuzhiyun pr_err("%s: corrupted context was not reset\n",
6316*4882a593Smuzhiyun engine->name);
6317*4882a593Smuzhiyun err = -EINVAL;
6318*4882a593Smuzhiyun goto err_ce;
6319*4882a593Smuzhiyun }
6320*4882a593Smuzhiyun
6321*4882a593Smuzhiyun if (i915_request_wait(hang, 0, HZ / 2) < 0) {
6322*4882a593Smuzhiyun pr_err("%s: corrupted context did not recover\n",
6323*4882a593Smuzhiyun engine->name);
6324*4882a593Smuzhiyun i915_request_put(hang);
6325*4882a593Smuzhiyun err = -EIO;
6326*4882a593Smuzhiyun goto err_ce;
6327*4882a593Smuzhiyun }
6328*4882a593Smuzhiyun i915_request_put(hang);
6329*4882a593Smuzhiyun
6330*4882a593Smuzhiyun err_ce:
6331*4882a593Smuzhiyun intel_context_put(ce);
6332*4882a593Smuzhiyun return err;
6333*4882a593Smuzhiyun }
6334*4882a593Smuzhiyun
live_lrc_garbage(void * arg)6335*4882a593Smuzhiyun static int live_lrc_garbage(void *arg)
6336*4882a593Smuzhiyun {
6337*4882a593Smuzhiyun struct intel_gt *gt = arg;
6338*4882a593Smuzhiyun struct intel_engine_cs *engine;
6339*4882a593Smuzhiyun enum intel_engine_id id;
6340*4882a593Smuzhiyun
6341*4882a593Smuzhiyun /*
6342*4882a593Smuzhiyun * Verify that we can recover if one context state is completely
6343*4882a593Smuzhiyun * corrupted.
6344*4882a593Smuzhiyun */
6345*4882a593Smuzhiyun
6346*4882a593Smuzhiyun if (!IS_ENABLED(CONFIG_DRM_I915_SELFTEST_BROKEN))
6347*4882a593Smuzhiyun return 0;
6348*4882a593Smuzhiyun
6349*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
6350*4882a593Smuzhiyun I915_RND_STATE(prng);
6351*4882a593Smuzhiyun int err = 0, i;
6352*4882a593Smuzhiyun
6353*4882a593Smuzhiyun if (!intel_has_reset_engine(engine->gt))
6354*4882a593Smuzhiyun continue;
6355*4882a593Smuzhiyun
6356*4882a593Smuzhiyun intel_engine_pm_get(engine);
6357*4882a593Smuzhiyun for (i = 0; i < 3; i++) {
6358*4882a593Smuzhiyun err = __lrc_garbage(engine, &prng);
6359*4882a593Smuzhiyun if (err)
6360*4882a593Smuzhiyun break;
6361*4882a593Smuzhiyun }
6362*4882a593Smuzhiyun intel_engine_pm_put(engine);
6363*4882a593Smuzhiyun
6364*4882a593Smuzhiyun if (igt_flush_test(gt->i915))
6365*4882a593Smuzhiyun err = -EIO;
6366*4882a593Smuzhiyun if (err)
6367*4882a593Smuzhiyun return err;
6368*4882a593Smuzhiyun }
6369*4882a593Smuzhiyun
6370*4882a593Smuzhiyun return 0;
6371*4882a593Smuzhiyun }
6372*4882a593Smuzhiyun
__live_pphwsp_runtime(struct intel_engine_cs * engine)6373*4882a593Smuzhiyun static int __live_pphwsp_runtime(struct intel_engine_cs *engine)
6374*4882a593Smuzhiyun {
6375*4882a593Smuzhiyun struct intel_context *ce;
6376*4882a593Smuzhiyun struct i915_request *rq;
6377*4882a593Smuzhiyun IGT_TIMEOUT(end_time);
6378*4882a593Smuzhiyun int err;
6379*4882a593Smuzhiyun
6380*4882a593Smuzhiyun ce = intel_context_create(engine);
6381*4882a593Smuzhiyun if (IS_ERR(ce))
6382*4882a593Smuzhiyun return PTR_ERR(ce);
6383*4882a593Smuzhiyun
6384*4882a593Smuzhiyun ce->runtime.num_underflow = 0;
6385*4882a593Smuzhiyun ce->runtime.max_underflow = 0;
6386*4882a593Smuzhiyun
6387*4882a593Smuzhiyun do {
6388*4882a593Smuzhiyun unsigned int loop = 1024;
6389*4882a593Smuzhiyun
6390*4882a593Smuzhiyun while (loop) {
6391*4882a593Smuzhiyun rq = intel_context_create_request(ce);
6392*4882a593Smuzhiyun if (IS_ERR(rq)) {
6393*4882a593Smuzhiyun err = PTR_ERR(rq);
6394*4882a593Smuzhiyun goto err_rq;
6395*4882a593Smuzhiyun }
6396*4882a593Smuzhiyun
6397*4882a593Smuzhiyun if (--loop == 0)
6398*4882a593Smuzhiyun i915_request_get(rq);
6399*4882a593Smuzhiyun
6400*4882a593Smuzhiyun i915_request_add(rq);
6401*4882a593Smuzhiyun }
6402*4882a593Smuzhiyun
6403*4882a593Smuzhiyun if (__igt_timeout(end_time, NULL))
6404*4882a593Smuzhiyun break;
6405*4882a593Smuzhiyun
6406*4882a593Smuzhiyun i915_request_put(rq);
6407*4882a593Smuzhiyun } while (1);
6408*4882a593Smuzhiyun
6409*4882a593Smuzhiyun err = i915_request_wait(rq, 0, HZ / 5);
6410*4882a593Smuzhiyun if (err < 0) {
6411*4882a593Smuzhiyun pr_err("%s: request not completed!\n", engine->name);
6412*4882a593Smuzhiyun goto err_wait;
6413*4882a593Smuzhiyun }
6414*4882a593Smuzhiyun
6415*4882a593Smuzhiyun igt_flush_test(engine->i915);
6416*4882a593Smuzhiyun
6417*4882a593Smuzhiyun pr_info("%s: pphwsp runtime %lluns, average %lluns\n",
6418*4882a593Smuzhiyun engine->name,
6419*4882a593Smuzhiyun intel_context_get_total_runtime_ns(ce),
6420*4882a593Smuzhiyun intel_context_get_avg_runtime_ns(ce));
6421*4882a593Smuzhiyun
6422*4882a593Smuzhiyun err = 0;
6423*4882a593Smuzhiyun if (ce->runtime.num_underflow) {
6424*4882a593Smuzhiyun pr_err("%s: pphwsp underflow %u time(s), max %u cycles!\n",
6425*4882a593Smuzhiyun engine->name,
6426*4882a593Smuzhiyun ce->runtime.num_underflow,
6427*4882a593Smuzhiyun ce->runtime.max_underflow);
6428*4882a593Smuzhiyun GEM_TRACE_DUMP();
6429*4882a593Smuzhiyun err = -EOVERFLOW;
6430*4882a593Smuzhiyun }
6431*4882a593Smuzhiyun
6432*4882a593Smuzhiyun err_wait:
6433*4882a593Smuzhiyun i915_request_put(rq);
6434*4882a593Smuzhiyun err_rq:
6435*4882a593Smuzhiyun intel_context_put(ce);
6436*4882a593Smuzhiyun return err;
6437*4882a593Smuzhiyun }
6438*4882a593Smuzhiyun
live_pphwsp_runtime(void * arg)6439*4882a593Smuzhiyun static int live_pphwsp_runtime(void *arg)
6440*4882a593Smuzhiyun {
6441*4882a593Smuzhiyun struct intel_gt *gt = arg;
6442*4882a593Smuzhiyun struct intel_engine_cs *engine;
6443*4882a593Smuzhiyun enum intel_engine_id id;
6444*4882a593Smuzhiyun int err = 0;
6445*4882a593Smuzhiyun
6446*4882a593Smuzhiyun /*
6447*4882a593Smuzhiyun * Check that cumulative context runtime as stored in the pphwsp[16]
6448*4882a593Smuzhiyun * is monotonic.
6449*4882a593Smuzhiyun */
6450*4882a593Smuzhiyun
6451*4882a593Smuzhiyun for_each_engine(engine, gt, id) {
6452*4882a593Smuzhiyun err = __live_pphwsp_runtime(engine);
6453*4882a593Smuzhiyun if (err)
6454*4882a593Smuzhiyun break;
6455*4882a593Smuzhiyun }
6456*4882a593Smuzhiyun
6457*4882a593Smuzhiyun if (igt_flush_test(gt->i915))
6458*4882a593Smuzhiyun err = -EIO;
6459*4882a593Smuzhiyun
6460*4882a593Smuzhiyun return err;
6461*4882a593Smuzhiyun }
6462*4882a593Smuzhiyun
intel_lrc_live_selftests(struct drm_i915_private * i915)6463*4882a593Smuzhiyun int intel_lrc_live_selftests(struct drm_i915_private *i915)
6464*4882a593Smuzhiyun {
6465*4882a593Smuzhiyun static const struct i915_subtest tests[] = {
6466*4882a593Smuzhiyun SUBTEST(live_lrc_layout),
6467*4882a593Smuzhiyun SUBTEST(live_lrc_fixed),
6468*4882a593Smuzhiyun SUBTEST(live_lrc_state),
6469*4882a593Smuzhiyun SUBTEST(live_lrc_gpr),
6470*4882a593Smuzhiyun SUBTEST(live_lrc_isolation),
6471*4882a593Smuzhiyun SUBTEST(live_lrc_timestamp),
6472*4882a593Smuzhiyun SUBTEST(live_lrc_garbage),
6473*4882a593Smuzhiyun SUBTEST(live_pphwsp_runtime),
6474*4882a593Smuzhiyun SUBTEST(live_lrc_indirect_ctx_bb),
6475*4882a593Smuzhiyun };
6476*4882a593Smuzhiyun
6477*4882a593Smuzhiyun if (!HAS_LOGICAL_RING_CONTEXTS(i915))
6478*4882a593Smuzhiyun return 0;
6479*4882a593Smuzhiyun
6480*4882a593Smuzhiyun return intel_gt_live_subtests(tests, &i915->gt);
6481*4882a593Smuzhiyun }
6482