1ee2413eeSMika Kuoppala // SPDX-License-Identifier: MIT
2ee2413eeSMika Kuoppala /*
3ee2413eeSMika Kuoppala  * Copyright © 2020 Intel Corporation
4ee2413eeSMika Kuoppala  */
5ee2413eeSMika Kuoppala 
6ee2413eeSMika Kuoppala #include "intel_engine_pm.h"
7ee2413eeSMika Kuoppala #include "selftests/igt_flush_test.h"
8ee2413eeSMika Kuoppala 
create_wally(struct intel_engine_cs * engine)9ee2413eeSMika Kuoppala static struct i915_vma *create_wally(struct intel_engine_cs *engine)
10ee2413eeSMika Kuoppala {
11ee2413eeSMika Kuoppala 	struct drm_i915_gem_object *obj;
12ee2413eeSMika Kuoppala 	struct i915_vma *vma;
13ee2413eeSMika Kuoppala 	u32 *cs;
14ee2413eeSMika Kuoppala 	int err;
15ee2413eeSMika Kuoppala 
16ee2413eeSMika Kuoppala 	obj = i915_gem_object_create_internal(engine->i915, 4096);
17ee2413eeSMika Kuoppala 	if (IS_ERR(obj))
18ee2413eeSMika Kuoppala 		return ERR_CAST(obj);
19ee2413eeSMika Kuoppala 
20ee2413eeSMika Kuoppala 	vma = i915_vma_instance(obj, engine->gt->vm, NULL);
21ee2413eeSMika Kuoppala 	if (IS_ERR(vma)) {
22ee2413eeSMika Kuoppala 		i915_gem_object_put(obj);
23ee2413eeSMika Kuoppala 		return vma;
24ee2413eeSMika Kuoppala 	}
25ee2413eeSMika Kuoppala 
26ee2413eeSMika Kuoppala 	err = i915_vma_pin(vma, 0, 0, PIN_USER | PIN_HIGH);
27ee2413eeSMika Kuoppala 	if (err) {
28ee2413eeSMika Kuoppala 		i915_gem_object_put(obj);
29ee2413eeSMika Kuoppala 		return ERR_PTR(err);
30ee2413eeSMika Kuoppala 	}
31ee2413eeSMika Kuoppala 
32cc328351SChris Wilson 	err = i915_vma_sync(vma);
33cc328351SChris Wilson 	if (err) {
34cc328351SChris Wilson 		i915_gem_object_put(obj);
35cc328351SChris Wilson 		return ERR_PTR(err);
36cc328351SChris Wilson 	}
37cc328351SChris Wilson 
389aa6de99SMaarten Lankhorst 	cs = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WC);
39ee2413eeSMika Kuoppala 	if (IS_ERR(cs)) {
40ee2413eeSMika Kuoppala 		i915_gem_object_put(obj);
41ee2413eeSMika Kuoppala 		return ERR_CAST(cs);
42ee2413eeSMika Kuoppala 	}
43ee2413eeSMika Kuoppala 
44c816723bSLucas De Marchi 	if (GRAPHICS_VER(engine->i915) >= 6) {
45ee2413eeSMika Kuoppala 		*cs++ = MI_STORE_DWORD_IMM_GEN4;
46ee2413eeSMika Kuoppala 		*cs++ = 0;
47c816723bSLucas De Marchi 	} else if (GRAPHICS_VER(engine->i915) >= 4) {
48ee2413eeSMika Kuoppala 		*cs++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
49ee2413eeSMika Kuoppala 		*cs++ = 0;
50ee2413eeSMika Kuoppala 	} else {
51ee2413eeSMika Kuoppala 		*cs++ = MI_STORE_DWORD_IMM | MI_MEM_VIRTUAL;
52ee2413eeSMika Kuoppala 	}
53*8e4ee5e8SChris Wilson 	*cs++ = i915_vma_offset(vma) + 4000;
54ee2413eeSMika Kuoppala 	*cs++ = STACK_MAGIC;
55ee2413eeSMika Kuoppala 
56ee2413eeSMika Kuoppala 	*cs++ = MI_BATCH_BUFFER_END;
579bad40a2SChris Wilson 
589bad40a2SChris Wilson 	i915_gem_object_flush_map(obj);
59ee2413eeSMika Kuoppala 	i915_gem_object_unpin_map(obj);
60ee2413eeSMika Kuoppala 
61ee2413eeSMika Kuoppala 	vma->private = intel_context_create(engine); /* dummy residuals */
62ee2413eeSMika Kuoppala 	if (IS_ERR(vma->private)) {
63ee2413eeSMika Kuoppala 		vma = ERR_CAST(vma->private);
64ee2413eeSMika Kuoppala 		i915_gem_object_put(obj);
65ee2413eeSMika Kuoppala 	}
66ee2413eeSMika Kuoppala 
67ee2413eeSMika Kuoppala 	return vma;
68ee2413eeSMika Kuoppala }
69ee2413eeSMika Kuoppala 
context_sync(struct intel_context * ce)70ee2413eeSMika Kuoppala static int context_sync(struct intel_context *ce)
71ee2413eeSMika Kuoppala {
72ee2413eeSMika Kuoppala 	struct i915_request *rq;
73ee2413eeSMika Kuoppala 	int err = 0;
74ee2413eeSMika Kuoppala 
75ee2413eeSMika Kuoppala 	rq = intel_context_create_request(ce);
76ee2413eeSMika Kuoppala 	if (IS_ERR(rq))
77ee2413eeSMika Kuoppala 		return PTR_ERR(rq);
78ee2413eeSMika Kuoppala 
79ee2413eeSMika Kuoppala 	i915_request_get(rq);
80ee2413eeSMika Kuoppala 	i915_request_add(rq);
81ee2413eeSMika Kuoppala 
82ee2413eeSMika Kuoppala 	if (i915_request_wait(rq, 0, HZ / 5) < 0)
83ee2413eeSMika Kuoppala 		err = -ETIME;
84ee2413eeSMika Kuoppala 	i915_request_put(rq);
85ee2413eeSMika Kuoppala 
86ee2413eeSMika Kuoppala 	return err;
87ee2413eeSMika Kuoppala }
88ee2413eeSMika Kuoppala 
new_context_sync(struct intel_engine_cs * engine)89ee2413eeSMika Kuoppala static int new_context_sync(struct intel_engine_cs *engine)
90ee2413eeSMika Kuoppala {
91ee2413eeSMika Kuoppala 	struct intel_context *ce;
92ee2413eeSMika Kuoppala 	int err;
93ee2413eeSMika Kuoppala 
94ee2413eeSMika Kuoppala 	ce = intel_context_create(engine);
95ee2413eeSMika Kuoppala 	if (IS_ERR(ce))
96ee2413eeSMika Kuoppala 		return PTR_ERR(ce);
97ee2413eeSMika Kuoppala 
98ee2413eeSMika Kuoppala 	err = context_sync(ce);
99ee2413eeSMika Kuoppala 	intel_context_put(ce);
100ee2413eeSMika Kuoppala 
101ee2413eeSMika Kuoppala 	return err;
102ee2413eeSMika Kuoppala }
103ee2413eeSMika Kuoppala 
mixed_contexts_sync(struct intel_engine_cs * engine,u32 * result)104ee2413eeSMika Kuoppala static int mixed_contexts_sync(struct intel_engine_cs *engine, u32 *result)
105ee2413eeSMika Kuoppala {
106ee2413eeSMika Kuoppala 	int pass;
107ee2413eeSMika Kuoppala 	int err;
108ee2413eeSMika Kuoppala 
109ee2413eeSMika Kuoppala 	for (pass = 0; pass < 2; pass++) {
110ee2413eeSMika Kuoppala 		WRITE_ONCE(*result, 0);
111ee2413eeSMika Kuoppala 		err = context_sync(engine->kernel_context);
112ee2413eeSMika Kuoppala 		if (err || READ_ONCE(*result)) {
113ee2413eeSMika Kuoppala 			if (!err) {
114ee2413eeSMika Kuoppala 				pr_err("pass[%d] wa_bb emitted for the kernel context\n",
115ee2413eeSMika Kuoppala 				       pass);
116ee2413eeSMika Kuoppala 				err = -EINVAL;
117ee2413eeSMika Kuoppala 			}
118ee2413eeSMika Kuoppala 			return err;
119ee2413eeSMika Kuoppala 		}
120ee2413eeSMika Kuoppala 
121ee2413eeSMika Kuoppala 		WRITE_ONCE(*result, 0);
122ee2413eeSMika Kuoppala 		err = new_context_sync(engine);
123ee2413eeSMika Kuoppala 		if (READ_ONCE(*result) != STACK_MAGIC) {
124ee2413eeSMika Kuoppala 			if (!err) {
125ee2413eeSMika Kuoppala 				pr_err("pass[%d] wa_bb *NOT* emitted after the kernel context\n",
126ee2413eeSMika Kuoppala 				       pass);
127ee2413eeSMika Kuoppala 				err = -EINVAL;
128ee2413eeSMika Kuoppala 			}
129ee2413eeSMika Kuoppala 			return err;
130ee2413eeSMika Kuoppala 		}
131ee2413eeSMika Kuoppala 
132ee2413eeSMika Kuoppala 		WRITE_ONCE(*result, 0);
133ee2413eeSMika Kuoppala 		err = new_context_sync(engine);
134ee2413eeSMika Kuoppala 		if (READ_ONCE(*result) != STACK_MAGIC) {
135ee2413eeSMika Kuoppala 			if (!err) {
136ee2413eeSMika Kuoppala 				pr_err("pass[%d] wa_bb *NOT* emitted for the user context switch\n",
137ee2413eeSMika Kuoppala 				       pass);
138ee2413eeSMika Kuoppala 				err = -EINVAL;
139ee2413eeSMika Kuoppala 			}
140ee2413eeSMika Kuoppala 			return err;
141ee2413eeSMika Kuoppala 		}
142ee2413eeSMika Kuoppala 	}
143ee2413eeSMika Kuoppala 
144ee2413eeSMika Kuoppala 	return 0;
145ee2413eeSMika Kuoppala }
146ee2413eeSMika Kuoppala 
double_context_sync_00(struct intel_engine_cs * engine,u32 * result)147ee2413eeSMika Kuoppala static int double_context_sync_00(struct intel_engine_cs *engine, u32 *result)
148ee2413eeSMika Kuoppala {
149ee2413eeSMika Kuoppala 	struct intel_context *ce;
150ee2413eeSMika Kuoppala 	int err, i;
151ee2413eeSMika Kuoppala 
152ee2413eeSMika Kuoppala 	ce = intel_context_create(engine);
153ee2413eeSMika Kuoppala 	if (IS_ERR(ce))
154ee2413eeSMika Kuoppala 		return PTR_ERR(ce);
155ee2413eeSMika Kuoppala 
156ee2413eeSMika Kuoppala 	for (i = 0; i < 2; i++) {
157ee2413eeSMika Kuoppala 		WRITE_ONCE(*result, 0);
158ee2413eeSMika Kuoppala 		err = context_sync(ce);
159ee2413eeSMika Kuoppala 		if (err)
160ee2413eeSMika Kuoppala 			break;
161ee2413eeSMika Kuoppala 	}
162ee2413eeSMika Kuoppala 	intel_context_put(ce);
163ee2413eeSMika Kuoppala 	if (err)
164ee2413eeSMika Kuoppala 		return err;
165ee2413eeSMika Kuoppala 
166ee2413eeSMika Kuoppala 	if (READ_ONCE(*result)) {
167ee2413eeSMika Kuoppala 		pr_err("wa_bb emitted between the same user context\n");
168ee2413eeSMika Kuoppala 		return -EINVAL;
169ee2413eeSMika Kuoppala 	}
170ee2413eeSMika Kuoppala 
171ee2413eeSMika Kuoppala 	return 0;
172ee2413eeSMika Kuoppala }
173ee2413eeSMika Kuoppala 
kernel_context_sync_00(struct intel_engine_cs * engine,u32 * result)174ee2413eeSMika Kuoppala static int kernel_context_sync_00(struct intel_engine_cs *engine, u32 *result)
175ee2413eeSMika Kuoppala {
176ee2413eeSMika Kuoppala 	struct intel_context *ce;
177ee2413eeSMika Kuoppala 	int err, i;
178ee2413eeSMika Kuoppala 
179ee2413eeSMika Kuoppala 	ce = intel_context_create(engine);
180ee2413eeSMika Kuoppala 	if (IS_ERR(ce))
181ee2413eeSMika Kuoppala 		return PTR_ERR(ce);
182ee2413eeSMika Kuoppala 
183ee2413eeSMika Kuoppala 	for (i = 0; i < 2; i++) {
184ee2413eeSMika Kuoppala 		WRITE_ONCE(*result, 0);
185ee2413eeSMika Kuoppala 		err = context_sync(ce);
186ee2413eeSMika Kuoppala 		if (err)
187ee2413eeSMika Kuoppala 			break;
188ee2413eeSMika Kuoppala 
189ee2413eeSMika Kuoppala 		err = context_sync(engine->kernel_context);
190ee2413eeSMika Kuoppala 		if (err)
191ee2413eeSMika Kuoppala 			break;
192ee2413eeSMika Kuoppala 	}
193ee2413eeSMika Kuoppala 	intel_context_put(ce);
194ee2413eeSMika Kuoppala 	if (err)
195ee2413eeSMika Kuoppala 		return err;
196ee2413eeSMika Kuoppala 
197ee2413eeSMika Kuoppala 	if (READ_ONCE(*result)) {
198ee2413eeSMika Kuoppala 		pr_err("wa_bb emitted between the same user context [with intervening kernel]\n");
199ee2413eeSMika Kuoppala 		return -EINVAL;
200ee2413eeSMika Kuoppala 	}
201ee2413eeSMika Kuoppala 
202ee2413eeSMika Kuoppala 	return 0;
203ee2413eeSMika Kuoppala }
204ee2413eeSMika Kuoppala 
__live_ctx_switch_wa(struct intel_engine_cs * engine)205ee2413eeSMika Kuoppala static int __live_ctx_switch_wa(struct intel_engine_cs *engine)
206ee2413eeSMika Kuoppala {
207ee2413eeSMika Kuoppala 	struct i915_vma *bb;
208ee2413eeSMika Kuoppala 	u32 *result;
209ee2413eeSMika Kuoppala 	int err;
210ee2413eeSMika Kuoppala 
211ee2413eeSMika Kuoppala 	bb = create_wally(engine);
212ee2413eeSMika Kuoppala 	if (IS_ERR(bb))
213ee2413eeSMika Kuoppala 		return PTR_ERR(bb);
214ee2413eeSMika Kuoppala 
2159aa6de99SMaarten Lankhorst 	result = i915_gem_object_pin_map_unlocked(bb->obj, I915_MAP_WC);
216ee2413eeSMika Kuoppala 	if (IS_ERR(result)) {
217ee2413eeSMika Kuoppala 		intel_context_put(bb->private);
218ee2413eeSMika Kuoppala 		i915_vma_unpin_and_release(&bb, 0);
219ee2413eeSMika Kuoppala 		return PTR_ERR(result);
220ee2413eeSMika Kuoppala 	}
221ee2413eeSMika Kuoppala 	result += 1000;
222ee2413eeSMika Kuoppala 
223ee2413eeSMika Kuoppala 	engine->wa_ctx.vma = bb;
224ee2413eeSMika Kuoppala 
225ee2413eeSMika Kuoppala 	err = mixed_contexts_sync(engine, result);
226ee2413eeSMika Kuoppala 	if (err)
227ee2413eeSMika Kuoppala 		goto out;
228ee2413eeSMika Kuoppala 
229ee2413eeSMika Kuoppala 	err = double_context_sync_00(engine, result);
230ee2413eeSMika Kuoppala 	if (err)
231ee2413eeSMika Kuoppala 		goto out;
232ee2413eeSMika Kuoppala 
233ee2413eeSMika Kuoppala 	err = kernel_context_sync_00(engine, result);
234ee2413eeSMika Kuoppala 	if (err)
235ee2413eeSMika Kuoppala 		goto out;
236ee2413eeSMika Kuoppala 
237ee2413eeSMika Kuoppala out:
238ee2413eeSMika Kuoppala 	intel_context_put(engine->wa_ctx.vma->private);
239ee2413eeSMika Kuoppala 	i915_vma_unpin_and_release(&engine->wa_ctx.vma, I915_VMA_RELEASE_MAP);
240ee2413eeSMika Kuoppala 	return err;
241ee2413eeSMika Kuoppala }
242ee2413eeSMika Kuoppala 
live_ctx_switch_wa(void * arg)243ee2413eeSMika Kuoppala static int live_ctx_switch_wa(void *arg)
244ee2413eeSMika Kuoppala {
245ee2413eeSMika Kuoppala 	struct intel_gt *gt = arg;
246ee2413eeSMika Kuoppala 	struct intel_engine_cs *engine;
247ee2413eeSMika Kuoppala 	enum intel_engine_id id;
248ee2413eeSMika Kuoppala 
249ee2413eeSMika Kuoppala 	/*
250ee2413eeSMika Kuoppala 	 * Exercise the inter-context wa batch.
251ee2413eeSMika Kuoppala 	 *
252ee2413eeSMika Kuoppala 	 * Between each user context we run a wa batch, and since it may
253ee2413eeSMika Kuoppala 	 * have implications for user visible state, we have to check that
254ee2413eeSMika Kuoppala 	 * we do actually execute it.
255ee2413eeSMika Kuoppala 	 *
256ee2413eeSMika Kuoppala 	 * The trick we use is to replace the normal wa batch with a custom
257ee2413eeSMika Kuoppala 	 * one that writes to a marker within it, and we can then look for
258ee2413eeSMika Kuoppala 	 * that marker to confirm if the batch was run when we expect it,
259ee2413eeSMika Kuoppala 	 * and equally important it was wasn't run when we don't!
260ee2413eeSMika Kuoppala 	 */
261ee2413eeSMika Kuoppala 
262ee2413eeSMika Kuoppala 	for_each_engine(engine, gt, id) {
263ee2413eeSMika Kuoppala 		struct i915_vma *saved_wa;
264ee2413eeSMika Kuoppala 		int err;
265ee2413eeSMika Kuoppala 
266ee2413eeSMika Kuoppala 		if (!intel_engine_can_store_dword(engine))
267ee2413eeSMika Kuoppala 			continue;
268ee2413eeSMika Kuoppala 
269c816723bSLucas De Marchi 		if (IS_GRAPHICS_VER(gt->i915, 4, 5))
270ee2413eeSMika Kuoppala 			continue; /* MI_STORE_DWORD is privileged! */
271ee2413eeSMika Kuoppala 
272ee2413eeSMika Kuoppala 		saved_wa = fetch_and_zero(&engine->wa_ctx.vma);
273ee2413eeSMika Kuoppala 
274ee2413eeSMika Kuoppala 		intel_engine_pm_get(engine);
275ee2413eeSMika Kuoppala 		err = __live_ctx_switch_wa(engine);
276ee2413eeSMika Kuoppala 		intel_engine_pm_put(engine);
277ee2413eeSMika Kuoppala 		if (igt_flush_test(gt->i915))
278ee2413eeSMika Kuoppala 			err = -EIO;
279ee2413eeSMika Kuoppala 
280ee2413eeSMika Kuoppala 		engine->wa_ctx.vma = saved_wa;
281ee2413eeSMika Kuoppala 		if (err)
282ee2413eeSMika Kuoppala 			return err;
283ee2413eeSMika Kuoppala 	}
284ee2413eeSMika Kuoppala 
285ee2413eeSMika Kuoppala 	return 0;
286ee2413eeSMika Kuoppala }
287ee2413eeSMika Kuoppala 
intel_ring_submission_live_selftests(struct drm_i915_private * i915)288ee2413eeSMika Kuoppala int intel_ring_submission_live_selftests(struct drm_i915_private *i915)
289ee2413eeSMika Kuoppala {
290ee2413eeSMika Kuoppala 	static const struct i915_subtest tests[] = {
291ee2413eeSMika Kuoppala 		SUBTEST(live_ctx_switch_wa),
292ee2413eeSMika Kuoppala 	};
293ee2413eeSMika Kuoppala 
294c14adcbdSMichał Winiarski 	if (to_gt(i915)->submission_method > INTEL_SUBMISSION_RING)
295ee2413eeSMika Kuoppala 		return 0;
296ee2413eeSMika Kuoppala 
297c14adcbdSMichał Winiarski 	return intel_gt_live_subtests(tests, to_gt(i915));
298ee2413eeSMika Kuoppala }
299