1 // SPDX-License-Identifier: MIT
3 * Copyright © 2020 Intel Corporation
6 #include "intel_engine_pm.h"
7 #include "selftests/igt_flush_test.h"
9 static struct i915_vma
*create_wally(struct intel_engine_cs
*engine
)
11 struct drm_i915_gem_object
*obj
;
16 obj
= i915_gem_object_create_internal(engine
->i915
, 4096);
20 vma
= i915_vma_instance(obj
, engine
->gt
->vm
, NULL
);
22 i915_gem_object_put(obj
);
26 err
= i915_vma_pin(vma
, 0, 0, PIN_USER
| PIN_HIGH
);
28 i915_gem_object_put(obj
);
32 err
= i915_vma_sync(vma
);
34 i915_gem_object_put(obj
);
38 cs
= i915_gem_object_pin_map(obj
, I915_MAP_WC
);
40 i915_gem_object_put(obj
);
44 if (INTEL_GEN(engine
->i915
) >= 6) {
45 *cs
++ = MI_STORE_DWORD_IMM_GEN4
;
47 } else if (INTEL_GEN(engine
->i915
) >= 4) {
48 *cs
++ = MI_STORE_DWORD_IMM_GEN4
| MI_USE_GGTT
;
51 *cs
++ = MI_STORE_DWORD_IMM
| MI_MEM_VIRTUAL
;
53 *cs
++ = vma
->node
.start
+ 4000;
56 *cs
++ = MI_BATCH_BUFFER_END
;
58 i915_gem_object_flush_map(obj
);
59 i915_gem_object_unpin_map(obj
);
61 vma
->private = intel_context_create(engine
); /* dummy residuals */
62 if (IS_ERR(vma
->private)) {
63 vma
= ERR_CAST(vma
->private);
64 i915_gem_object_put(obj
);
70 static int context_sync(struct intel_context
*ce
)
72 struct i915_request
*rq
;
75 rq
= intel_context_create_request(ce
);
82 if (i915_request_wait(rq
, 0, HZ
/ 5) < 0)
89 static int new_context_sync(struct intel_engine_cs
*engine
)
91 struct intel_context
*ce
;
94 ce
= intel_context_create(engine
);
98 err
= context_sync(ce
);
99 intel_context_put(ce
);
104 static int mixed_contexts_sync(struct intel_engine_cs
*engine
, u32
*result
)
109 for (pass
= 0; pass
< 2; pass
++) {
110 WRITE_ONCE(*result
, 0);
111 err
= context_sync(engine
->kernel_context
);
112 if (err
|| READ_ONCE(*result
)) {
114 pr_err("pass[%d] wa_bb emitted for the kernel context\n",
121 WRITE_ONCE(*result
, 0);
122 err
= new_context_sync(engine
);
123 if (READ_ONCE(*result
) != STACK_MAGIC
) {
125 pr_err("pass[%d] wa_bb *NOT* emitted after the kernel context\n",
132 WRITE_ONCE(*result
, 0);
133 err
= new_context_sync(engine
);
134 if (READ_ONCE(*result
) != STACK_MAGIC
) {
136 pr_err("pass[%d] wa_bb *NOT* emitted for the user context switch\n",
147 static int double_context_sync_00(struct intel_engine_cs
*engine
, u32
*result
)
149 struct intel_context
*ce
;
152 ce
= intel_context_create(engine
);
156 for (i
= 0; i
< 2; i
++) {
157 WRITE_ONCE(*result
, 0);
158 err
= context_sync(ce
);
162 intel_context_put(ce
);
166 if (READ_ONCE(*result
)) {
167 pr_err("wa_bb emitted between the same user context\n");
174 static int kernel_context_sync_00(struct intel_engine_cs
*engine
, u32
*result
)
176 struct intel_context
*ce
;
179 ce
= intel_context_create(engine
);
183 for (i
= 0; i
< 2; i
++) {
184 WRITE_ONCE(*result
, 0);
185 err
= context_sync(ce
);
189 err
= context_sync(engine
->kernel_context
);
193 intel_context_put(ce
);
197 if (READ_ONCE(*result
)) {
198 pr_err("wa_bb emitted between the same user context [with intervening kernel]\n");
205 static int __live_ctx_switch_wa(struct intel_engine_cs
*engine
)
211 bb
= create_wally(engine
);
215 result
= i915_gem_object_pin_map(bb
->obj
, I915_MAP_WC
);
216 if (IS_ERR(result
)) {
217 intel_context_put(bb
->private);
218 i915_vma_unpin_and_release(&bb
, 0);
219 return PTR_ERR(result
);
223 engine
->wa_ctx
.vma
= bb
;
225 err
= mixed_contexts_sync(engine
, result
);
229 err
= double_context_sync_00(engine
, result
);
233 err
= kernel_context_sync_00(engine
, result
);
238 intel_context_put(engine
->wa_ctx
.vma
->private);
239 i915_vma_unpin_and_release(&engine
->wa_ctx
.vma
, I915_VMA_RELEASE_MAP
);
243 static int live_ctx_switch_wa(void *arg
)
245 struct intel_gt
*gt
= arg
;
246 struct intel_engine_cs
*engine
;
247 enum intel_engine_id id
;
250 * Exercise the inter-context wa batch.
252 * Between each user context we run a wa batch, and since it may
253 * have implications for user visible state, we have to check that
254 * we do actually execute it.
256 * The trick we use is to replace the normal wa batch with a custom
257 * one that writes to a marker within it, and we can then look for
258 * that marker to confirm if the batch was run when we expect it,
259 * and equally important it was wasn't run when we don't!
262 for_each_engine(engine
, gt
, id
) {
263 struct i915_vma
*saved_wa
;
266 if (!intel_engine_can_store_dword(engine
))
269 if (IS_GEN_RANGE(gt
->i915
, 4, 5))
270 continue; /* MI_STORE_DWORD is privileged! */
272 saved_wa
= fetch_and_zero(&engine
->wa_ctx
.vma
);
274 intel_engine_pm_get(engine
);
275 err
= __live_ctx_switch_wa(engine
);
276 intel_engine_pm_put(engine
);
277 if (igt_flush_test(gt
->i915
))
280 engine
->wa_ctx
.vma
= saved_wa
;
288 int intel_ring_submission_live_selftests(struct drm_i915_private
*i915
)
290 static const struct i915_subtest tests
[] = {
291 SUBTEST(live_ctx_switch_wa
),
294 if (HAS_EXECLISTS(i915
))
297 return intel_gt_live_subtests(tests
, &i915
->gt
);