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