Skip to content

Commit ed2690a

Browse files
committed
drm/i915/selftest: Check that GPR are restored across noa_wait
Perf implements a GPU delay (noa_wait) by looping until the CS timestamp has passed a certain point. This use MI_MATH and the general purpose registers of the user's context, and since it is clobbering the user state it must carefully save and restore the user's data around the noa_wait. We can verify this by loading some values in the GPR that we know will be clobbered by the noa_wait, and then inspecting the GPR after the noa_wait completes and confirming that they have been restored. Signed-off-by: Chris Wilson <[email protected]> Cc: Umesh Nerlige Ramappa <[email protected]> Cc: Lionel Landwerlin <[email protected]> Reviewed-by: Lionel Landwerlin <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent e43ff99 commit ed2690a

File tree

1 file changed

+131
-0
lines changed

1 file changed

+131
-0
lines changed

drivers/gpu/drm/i915/selftests/i915_perf.c

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,11 +280,142 @@ static int live_noa_delay(void *arg)
280280
return err;
281281
}
282282

283+
static int live_noa_gpr(void *arg)
284+
{
285+
struct drm_i915_private *i915 = arg;
286+
struct i915_perf_stream *stream;
287+
struct intel_context *ce;
288+
struct i915_request *rq;
289+
u32 *cs, *store;
290+
void *scratch;
291+
u32 gpr0;
292+
int err;
293+
int i;
294+
295+
/* Check that the delay does not clobber user context state (GPR) */
296+
297+
stream = test_stream(&i915->perf);
298+
if (!stream)
299+
return -ENOMEM;
300+
301+
gpr0 = i915_mmio_reg_offset(GEN8_RING_CS_GPR(stream->engine->mmio_base, 0));
302+
303+
ce = intel_context_create(stream->engine);
304+
if (IS_ERR(ce)) {
305+
err = PTR_ERR(ce);
306+
goto out;
307+
}
308+
309+
/* Poison the ce->vm so we detect writes not to the GGTT gt->scratch */
310+
scratch = kmap(ce->vm->scratch[0].base.page);
311+
memset(scratch, POISON_FREE, PAGE_SIZE);
312+
313+
rq = intel_context_create_request(ce);
314+
if (IS_ERR(rq)) {
315+
err = PTR_ERR(rq);
316+
goto out_ce;
317+
}
318+
i915_request_get(rq);
319+
320+
if (rq->engine->emit_init_breadcrumb) {
321+
err = rq->engine->emit_init_breadcrumb(rq);
322+
if (err) {
323+
i915_request_add(rq);
324+
goto out_rq;
325+
}
326+
}
327+
328+
/* Fill the 16 qword [32 dword] GPR with a known unlikely value */
329+
cs = intel_ring_begin(rq, 2 * 32 + 2);
330+
if (IS_ERR(cs)) {
331+
i915_request_add(rq);
332+
goto out_rq;
333+
}
334+
335+
*cs++ = MI_LOAD_REGISTER_IMM(32);
336+
for (i = 0; i < 32; i++) {
337+
*cs++ = gpr0 + i * sizeof(u32);
338+
*cs++ = STACK_MAGIC;
339+
}
340+
*cs++ = MI_NOOP;
341+
intel_ring_advance(rq, cs);
342+
343+
/* Execute the GPU delay */
344+
err = rq->engine->emit_bb_start(rq,
345+
i915_ggtt_offset(stream->noa_wait), 0,
346+
I915_DISPATCH_SECURE);
347+
if (err) {
348+
i915_request_add(rq);
349+
goto out_rq;
350+
}
351+
352+
/* Read the GPR back, using the pinned global HWSP for convenience */
353+
store = memset32(rq->engine->status_page.addr + 512, 0, 32);
354+
for (i = 0; i < 32; i++) {
355+
u32 cmd;
356+
357+
cs = intel_ring_begin(rq, 4);
358+
if (IS_ERR(cs)) {
359+
i915_request_add(rq);
360+
goto out_rq;
361+
}
362+
363+
cmd = MI_STORE_REGISTER_MEM;
364+
if (INTEL_GEN(i915) >= 8)
365+
cmd++;
366+
cmd |= MI_USE_GGTT;
367+
368+
*cs++ = cmd;
369+
*cs++ = gpr0 + i * sizeof(u32);
370+
*cs++ = i915_ggtt_offset(rq->engine->status_page.vma) +
371+
offset_in_page(store) +
372+
i * sizeof(u32);
373+
*cs++ = 0;
374+
intel_ring_advance(rq, cs);
375+
}
376+
377+
i915_request_add(rq);
378+
379+
if (i915_request_wait(rq, I915_WAIT_INTERRUPTIBLE, HZ / 2) < 0) {
380+
pr_err("noa_wait timed out\n");
381+
intel_gt_set_wedged(stream->engine->gt);
382+
err = -EIO;
383+
goto out_rq;
384+
}
385+
386+
/* Verify that the GPR contain our expected values */
387+
for (i = 0; i < 32; i++) {
388+
if (store[i] == STACK_MAGIC)
389+
continue;
390+
391+
pr_err("GPR[%d] lost, found:%08x, expected:%08x!\n",
392+
i, store[i], STACK_MAGIC);
393+
err = -EINVAL;
394+
}
395+
396+
/* Verify that the user's scratch page was not used for GPR storage */
397+
if (memchr_inv(scratch, POISON_FREE, PAGE_SIZE)) {
398+
pr_err("Scratch page overwritten!\n");
399+
igt_hexdump(scratch, 4096);
400+
err = -EINVAL;
401+
}
402+
403+
out_rq:
404+
i915_request_put(rq);
405+
out_ce:
406+
kunmap(ce->vm->scratch[0].base.page);
407+
intel_context_put(ce);
408+
out:
409+
stream_destroy(stream);
410+
return err;
411+
}
412+
283413
int i915_perf_live_selftests(struct drm_i915_private *i915)
284414
{
285415
static const struct i915_subtest tests[] = {
286416
SUBTEST(live_sanitycheck),
287417
SUBTEST(live_noa_delay),
418+
SUBTEST(live_noa_gpr),
288419
};
289420
struct i915_perf *perf = &i915->perf;
290421
int err;

0 commit comments

Comments
 (0)