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