xref: /openbmc/linux/drivers/gpu/drm/i915/selftests/i915_perf.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1daed3e44SLionel Landwerlin /*
2daed3e44SLionel Landwerlin  * SPDX-License-Identifier: MIT
3daed3e44SLionel Landwerlin  *
4daed3e44SLionel Landwerlin  * Copyright © 2019 Intel Corporation
5daed3e44SLionel Landwerlin  */
6daed3e44SLionel Landwerlin 
7daed3e44SLionel Landwerlin #include <linux/kref.h>
8daed3e44SLionel Landwerlin 
9daed3e44SLionel Landwerlin #include "gem/i915_gem_pm.h"
10daed3e44SLionel Landwerlin #include "gt/intel_gt.h"
11daed3e44SLionel Landwerlin 
12daed3e44SLionel Landwerlin #include "i915_selftest.h"
13daed3e44SLionel Landwerlin 
14daed3e44SLionel Landwerlin #include "igt_flush_test.h"
15daed3e44SLionel Landwerlin #include "lib_sw_fence.h"
16daed3e44SLionel Landwerlin 
179aba9c18SLionel Landwerlin #define TEST_OA_CONFIG_UUID "12345678-1234-1234-1234-1234567890ab"
189aba9c18SLionel Landwerlin 
199aba9c18SLionel Landwerlin static int
alloc_empty_config(struct i915_perf * perf)209aba9c18SLionel Landwerlin alloc_empty_config(struct i915_perf *perf)
219aba9c18SLionel Landwerlin {
229aba9c18SLionel Landwerlin 	struct i915_oa_config *oa_config;
239aba9c18SLionel Landwerlin 
249aba9c18SLionel Landwerlin 	oa_config = kzalloc(sizeof(*oa_config), GFP_KERNEL);
259aba9c18SLionel Landwerlin 	if (!oa_config)
269aba9c18SLionel Landwerlin 		return -ENOMEM;
279aba9c18SLionel Landwerlin 
289aba9c18SLionel Landwerlin 	oa_config->perf = perf;
299aba9c18SLionel Landwerlin 	kref_init(&oa_config->ref);
309aba9c18SLionel Landwerlin 
319a2cb1b3SAzeem Shaikh 	strscpy(oa_config->uuid, TEST_OA_CONFIG_UUID, sizeof(oa_config->uuid));
329aba9c18SLionel Landwerlin 
339aba9c18SLionel Landwerlin 	mutex_lock(&perf->metrics_lock);
349aba9c18SLionel Landwerlin 
359aba9c18SLionel Landwerlin 	oa_config->id = idr_alloc(&perf->metrics_idr, oa_config, 2, 0, GFP_KERNEL);
369aba9c18SLionel Landwerlin 	if (oa_config->id < 0)  {
379aba9c18SLionel Landwerlin 		mutex_unlock(&perf->metrics_lock);
389aba9c18SLionel Landwerlin 		i915_oa_config_put(oa_config);
399aba9c18SLionel Landwerlin 		return -ENOMEM;
409aba9c18SLionel Landwerlin 	}
419aba9c18SLionel Landwerlin 
429aba9c18SLionel Landwerlin 	mutex_unlock(&perf->metrics_lock);
439aba9c18SLionel Landwerlin 
449aba9c18SLionel Landwerlin 	return 0;
459aba9c18SLionel Landwerlin }
469aba9c18SLionel Landwerlin 
479aba9c18SLionel Landwerlin static void
destroy_empty_config(struct i915_perf * perf)489aba9c18SLionel Landwerlin destroy_empty_config(struct i915_perf *perf)
499aba9c18SLionel Landwerlin {
509aba9c18SLionel Landwerlin 	struct i915_oa_config *oa_config = NULL, *tmp;
519aba9c18SLionel Landwerlin 	int id;
529aba9c18SLionel Landwerlin 
539aba9c18SLionel Landwerlin 	mutex_lock(&perf->metrics_lock);
549aba9c18SLionel Landwerlin 
559aba9c18SLionel Landwerlin 	idr_for_each_entry(&perf->metrics_idr, tmp, id) {
569aba9c18SLionel Landwerlin 		if (!strcmp(tmp->uuid, TEST_OA_CONFIG_UUID)) {
579aba9c18SLionel Landwerlin 			oa_config = tmp;
589aba9c18SLionel Landwerlin 			break;
599aba9c18SLionel Landwerlin 		}
609aba9c18SLionel Landwerlin 	}
619aba9c18SLionel Landwerlin 
629aba9c18SLionel Landwerlin 	if (oa_config)
639aba9c18SLionel Landwerlin 		idr_remove(&perf->metrics_idr, oa_config->id);
649aba9c18SLionel Landwerlin 
659aba9c18SLionel Landwerlin 	mutex_unlock(&perf->metrics_lock);
669aba9c18SLionel Landwerlin 
679aba9c18SLionel Landwerlin 	if (oa_config)
689aba9c18SLionel Landwerlin 		i915_oa_config_put(oa_config);
699aba9c18SLionel Landwerlin }
709aba9c18SLionel Landwerlin 
719aba9c18SLionel Landwerlin static struct i915_oa_config *
get_empty_config(struct i915_perf * perf)729aba9c18SLionel Landwerlin get_empty_config(struct i915_perf *perf)
739aba9c18SLionel Landwerlin {
749aba9c18SLionel Landwerlin 	struct i915_oa_config *oa_config = NULL, *tmp;
759aba9c18SLionel Landwerlin 	int id;
769aba9c18SLionel Landwerlin 
779aba9c18SLionel Landwerlin 	mutex_lock(&perf->metrics_lock);
789aba9c18SLionel Landwerlin 
799aba9c18SLionel Landwerlin 	idr_for_each_entry(&perf->metrics_idr, tmp, id) {
809aba9c18SLionel Landwerlin 		if (!strcmp(tmp->uuid, TEST_OA_CONFIG_UUID)) {
819aba9c18SLionel Landwerlin 			oa_config = i915_oa_config_get(tmp);
829aba9c18SLionel Landwerlin 			break;
839aba9c18SLionel Landwerlin 		}
849aba9c18SLionel Landwerlin 	}
859aba9c18SLionel Landwerlin 
869aba9c18SLionel Landwerlin 	mutex_unlock(&perf->metrics_lock);
879aba9c18SLionel Landwerlin 
889aba9c18SLionel Landwerlin 	return oa_config;
899aba9c18SLionel Landwerlin }
909aba9c18SLionel Landwerlin 
91daed3e44SLionel Landwerlin static struct i915_perf_stream *
test_stream(struct i915_perf * perf)92daed3e44SLionel Landwerlin test_stream(struct i915_perf *perf)
93daed3e44SLionel Landwerlin {
94daed3e44SLionel Landwerlin 	struct drm_i915_perf_open_param param = {};
959aba9c18SLionel Landwerlin 	struct i915_oa_config *oa_config = get_empty_config(perf);
96daed3e44SLionel Landwerlin 	struct perf_open_properties props = {
97daed3e44SLionel Landwerlin 		.engine = intel_engine_lookup_user(perf->i915,
98daed3e44SLionel Landwerlin 						   I915_ENGINE_CLASS_RENDER,
99daed3e44SLionel Landwerlin 						   0),
100daed3e44SLionel Landwerlin 		.sample_flags = SAMPLE_OA_REPORT,
101651e7d48SLucas De Marchi 		.oa_format = GRAPHICS_VER(perf->i915) == 12 ?
102bf96b515SLionel Landwerlin 		I915_OA_FORMAT_A32u40_A4u32_B8_C8 : I915_OA_FORMAT_C4_B8,
103daed3e44SLionel Landwerlin 	};
104daed3e44SLionel Landwerlin 	struct i915_perf_stream *stream;
1059677a9f3SUmesh Nerlige Ramappa 	struct intel_gt *gt;
1069677a9f3SUmesh Nerlige Ramappa 
1079677a9f3SUmesh Nerlige Ramappa 	if (!props.engine)
1089677a9f3SUmesh Nerlige Ramappa 		return NULL;
1099677a9f3SUmesh Nerlige Ramappa 
1109677a9f3SUmesh Nerlige Ramappa 	gt = props.engine->gt;
111daed3e44SLionel Landwerlin 
1129aba9c18SLionel Landwerlin 	if (!oa_config)
113daed3e44SLionel Landwerlin 		return NULL;
114daed3e44SLionel Landwerlin 
1159aba9c18SLionel Landwerlin 	props.metrics_set = oa_config->id;
1169aba9c18SLionel Landwerlin 
1179aba9c18SLionel Landwerlin 	stream = kzalloc(sizeof(*stream), GFP_KERNEL);
1189aba9c18SLionel Landwerlin 	if (!stream) {
1199aba9c18SLionel Landwerlin 		i915_oa_config_put(oa_config);
1209aba9c18SLionel Landwerlin 		return NULL;
1219aba9c18SLionel Landwerlin 	}
1229aba9c18SLionel Landwerlin 
123daed3e44SLionel Landwerlin 	stream->perf = perf;
124daed3e44SLionel Landwerlin 
1259677a9f3SUmesh Nerlige Ramappa 	mutex_lock(&gt->perf.lock);
126daed3e44SLionel Landwerlin 	if (i915_oa_stream_init(stream, &param, &props)) {
127daed3e44SLionel Landwerlin 		kfree(stream);
128daed3e44SLionel Landwerlin 		stream =  NULL;
129daed3e44SLionel Landwerlin 	}
1309677a9f3SUmesh Nerlige Ramappa 	mutex_unlock(&gt->perf.lock);
131daed3e44SLionel Landwerlin 
1329aba9c18SLionel Landwerlin 	i915_oa_config_put(oa_config);
1339aba9c18SLionel Landwerlin 
134daed3e44SLionel Landwerlin 	return stream;
135daed3e44SLionel Landwerlin }
136daed3e44SLionel Landwerlin 
stream_destroy(struct i915_perf_stream * stream)137daed3e44SLionel Landwerlin static void stream_destroy(struct i915_perf_stream *stream)
138daed3e44SLionel Landwerlin {
1399677a9f3SUmesh Nerlige Ramappa 	struct intel_gt *gt = stream->engine->gt;
140daed3e44SLionel Landwerlin 
1419677a9f3SUmesh Nerlige Ramappa 	mutex_lock(&gt->perf.lock);
142daed3e44SLionel Landwerlin 	i915_perf_destroy_locked(stream);
1439677a9f3SUmesh Nerlige Ramappa 	mutex_unlock(&gt->perf.lock);
144daed3e44SLionel Landwerlin }
145daed3e44SLionel Landwerlin 
live_sanitycheck(void * arg)146daed3e44SLionel Landwerlin static int live_sanitycheck(void *arg)
147daed3e44SLionel Landwerlin {
148daed3e44SLionel Landwerlin 	struct drm_i915_private *i915 = arg;
149daed3e44SLionel Landwerlin 	struct i915_perf_stream *stream;
150daed3e44SLionel Landwerlin 
151daed3e44SLionel Landwerlin 	/* Quick check we can create a perf stream */
152daed3e44SLionel Landwerlin 
153daed3e44SLionel Landwerlin 	stream = test_stream(&i915->perf);
154daed3e44SLionel Landwerlin 	if (!stream)
155daed3e44SLionel Landwerlin 		return -EINVAL;
156daed3e44SLionel Landwerlin 
157daed3e44SLionel Landwerlin 	stream_destroy(stream);
158daed3e44SLionel Landwerlin 	return 0;
159daed3e44SLionel Landwerlin }
160daed3e44SLionel Landwerlin 
write_timestamp(struct i915_request * rq,int slot)161daed3e44SLionel Landwerlin static int write_timestamp(struct i915_request *rq, int slot)
162daed3e44SLionel Landwerlin {
163daed3e44SLionel Landwerlin 	u32 *cs;
164daed3e44SLionel Landwerlin 	int len;
165daed3e44SLionel Landwerlin 
166daed3e44SLionel Landwerlin 	cs = intel_ring_begin(rq, 6);
167daed3e44SLionel Landwerlin 	if (IS_ERR(cs))
168daed3e44SLionel Landwerlin 		return PTR_ERR(cs);
169daed3e44SLionel Landwerlin 
170daed3e44SLionel Landwerlin 	len = 5;
171*d3f23ab9SAndrzej Hajda 	if (GRAPHICS_VER(rq->i915) >= 8)
172daed3e44SLionel Landwerlin 		len++;
173daed3e44SLionel Landwerlin 
174daed3e44SLionel Landwerlin 	*cs++ = GFX_OP_PIPE_CONTROL(len);
175daed3e44SLionel Landwerlin 	*cs++ = PIPE_CONTROL_GLOBAL_GTT_IVB |
176daed3e44SLionel Landwerlin 		PIPE_CONTROL_STORE_DATA_INDEX |
177daed3e44SLionel Landwerlin 		PIPE_CONTROL_WRITE_TIMESTAMP;
178daed3e44SLionel Landwerlin 	*cs++ = slot * sizeof(u32);
179daed3e44SLionel Landwerlin 	*cs++ = 0;
180daed3e44SLionel Landwerlin 	*cs++ = 0;
181daed3e44SLionel Landwerlin 	*cs++ = 0;
182daed3e44SLionel Landwerlin 
183daed3e44SLionel Landwerlin 	intel_ring_advance(rq, cs);
184daed3e44SLionel Landwerlin 
185daed3e44SLionel Landwerlin 	return 0;
186daed3e44SLionel Landwerlin }
187daed3e44SLionel Landwerlin 
poll_status(struct i915_request * rq,int slot)188daed3e44SLionel Landwerlin static ktime_t poll_status(struct i915_request *rq, int slot)
189daed3e44SLionel Landwerlin {
190daed3e44SLionel Landwerlin 	while (!intel_read_status_page(rq->engine, slot) &&
191daed3e44SLionel Landwerlin 	       !i915_request_completed(rq))
192daed3e44SLionel Landwerlin 		cpu_relax();
193daed3e44SLionel Landwerlin 
194daed3e44SLionel Landwerlin 	return ktime_get();
195daed3e44SLionel Landwerlin }
196daed3e44SLionel Landwerlin 
live_noa_delay(void * arg)197daed3e44SLionel Landwerlin static int live_noa_delay(void *arg)
198daed3e44SLionel Landwerlin {
199daed3e44SLionel Landwerlin 	struct drm_i915_private *i915 = arg;
200daed3e44SLionel Landwerlin 	struct i915_perf_stream *stream;
201daed3e44SLionel Landwerlin 	struct i915_request *rq;
202daed3e44SLionel Landwerlin 	ktime_t t0, t1;
203daed3e44SLionel Landwerlin 	u64 expected;
204daed3e44SLionel Landwerlin 	u32 delay;
205daed3e44SLionel Landwerlin 	int err;
206daed3e44SLionel Landwerlin 	int i;
207daed3e44SLionel Landwerlin 
208daed3e44SLionel Landwerlin 	/* Check that the GPU delays matches expectations */
209daed3e44SLionel Landwerlin 
210daed3e44SLionel Landwerlin 	stream = test_stream(&i915->perf);
211daed3e44SLionel Landwerlin 	if (!stream)
212daed3e44SLionel Landwerlin 		return -ENOMEM;
213daed3e44SLionel Landwerlin 
214daed3e44SLionel Landwerlin 	expected = atomic64_read(&stream->perf->noa_programming_delay);
215daed3e44SLionel Landwerlin 
216daed3e44SLionel Landwerlin 	if (stream->engine->class != RENDER_CLASS) {
217daed3e44SLionel Landwerlin 		err = -ENODEV;
218daed3e44SLionel Landwerlin 		goto out;
219daed3e44SLionel Landwerlin 	}
220daed3e44SLionel Landwerlin 
221daed3e44SLionel Landwerlin 	for (i = 0; i < 4; i++)
222daed3e44SLionel Landwerlin 		intel_write_status_page(stream->engine, 0x100 + i, 0);
223daed3e44SLionel Landwerlin 
224de5825beSChris Wilson 	rq = intel_engine_create_kernel_request(stream->engine);
225daed3e44SLionel Landwerlin 	if (IS_ERR(rq)) {
226daed3e44SLionel Landwerlin 		err = PTR_ERR(rq);
227daed3e44SLionel Landwerlin 		goto out;
228daed3e44SLionel Landwerlin 	}
229daed3e44SLionel Landwerlin 
230ed610f43SChris Wilson 	if (rq->engine->emit_init_breadcrumb) {
231daed3e44SLionel Landwerlin 		err = rq->engine->emit_init_breadcrumb(rq);
232daed3e44SLionel Landwerlin 		if (err) {
233daed3e44SLionel Landwerlin 			i915_request_add(rq);
234daed3e44SLionel Landwerlin 			goto out;
235daed3e44SLionel Landwerlin 		}
236daed3e44SLionel Landwerlin 	}
237daed3e44SLionel Landwerlin 
238daed3e44SLionel Landwerlin 	err = write_timestamp(rq, 0x100);
239daed3e44SLionel Landwerlin 	if (err) {
240daed3e44SLionel Landwerlin 		i915_request_add(rq);
241daed3e44SLionel Landwerlin 		goto out;
242daed3e44SLionel Landwerlin 	}
243daed3e44SLionel Landwerlin 
244daed3e44SLionel Landwerlin 	err = rq->engine->emit_bb_start(rq,
245daed3e44SLionel Landwerlin 					i915_ggtt_offset(stream->noa_wait), 0,
246daed3e44SLionel Landwerlin 					I915_DISPATCH_SECURE);
247daed3e44SLionel Landwerlin 	if (err) {
248daed3e44SLionel Landwerlin 		i915_request_add(rq);
249daed3e44SLionel Landwerlin 		goto out;
250daed3e44SLionel Landwerlin 	}
251daed3e44SLionel Landwerlin 
252daed3e44SLionel Landwerlin 	err = write_timestamp(rq, 0x102);
253daed3e44SLionel Landwerlin 	if (err) {
254daed3e44SLionel Landwerlin 		i915_request_add(rq);
255daed3e44SLionel Landwerlin 		goto out;
256daed3e44SLionel Landwerlin 	}
257daed3e44SLionel Landwerlin 
258daed3e44SLionel Landwerlin 	i915_request_get(rq);
259daed3e44SLionel Landwerlin 	i915_request_add(rq);
260daed3e44SLionel Landwerlin 
261daed3e44SLionel Landwerlin 	preempt_disable();
262daed3e44SLionel Landwerlin 	t0 = poll_status(rq, 0x100);
263daed3e44SLionel Landwerlin 	t1 = poll_status(rq, 0x102);
264daed3e44SLionel Landwerlin 	preempt_enable();
265daed3e44SLionel Landwerlin 
266daed3e44SLionel Landwerlin 	pr_info("CPU delay: %lluns, expected %lluns\n",
267daed3e44SLionel Landwerlin 		ktime_sub(t1, t0), expected);
268daed3e44SLionel Landwerlin 
269daed3e44SLionel Landwerlin 	delay = intel_read_status_page(stream->engine, 0x102);
270daed3e44SLionel Landwerlin 	delay -= intel_read_status_page(stream->engine, 0x100);
271f170523aSChris Wilson 	delay = intel_gt_clock_interval_to_ns(stream->engine->gt, delay);
272daed3e44SLionel Landwerlin 	pr_info("GPU delay: %uns, expected %lluns\n",
273daed3e44SLionel Landwerlin 		delay, expected);
274daed3e44SLionel Landwerlin 
275daed3e44SLionel Landwerlin 	if (4 * delay < 3 * expected || 2 * delay > 3 * expected) {
276daed3e44SLionel Landwerlin 		pr_err("GPU delay [%uus] outside of expected threshold! [%lluus, %lluus]\n",
277daed3e44SLionel Landwerlin 		       delay / 1000,
278daed3e44SLionel Landwerlin 		       div_u64(3 * expected, 4000),
279daed3e44SLionel Landwerlin 		       div_u64(3 * expected, 2000));
280daed3e44SLionel Landwerlin 		err = -EINVAL;
281daed3e44SLionel Landwerlin 	}
282daed3e44SLionel Landwerlin 
283daed3e44SLionel Landwerlin 	i915_request_put(rq);
284daed3e44SLionel Landwerlin out:
285daed3e44SLionel Landwerlin 	stream_destroy(stream);
286daed3e44SLionel Landwerlin 	return err;
287daed3e44SLionel Landwerlin }
288daed3e44SLionel Landwerlin 
live_noa_gpr(void * arg)289ed2690a9SChris Wilson static int live_noa_gpr(void *arg)
290ed2690a9SChris Wilson {
291ed2690a9SChris Wilson 	struct drm_i915_private *i915 = arg;
292ed2690a9SChris Wilson 	struct i915_perf_stream *stream;
293ed2690a9SChris Wilson 	struct intel_context *ce;
294ed2690a9SChris Wilson 	struct i915_request *rq;
295ed2690a9SChris Wilson 	u32 *cs, *store;
296ed2690a9SChris Wilson 	void *scratch;
297ed2690a9SChris Wilson 	u32 gpr0;
298ed2690a9SChris Wilson 	int err;
299ed2690a9SChris Wilson 	int i;
300ed2690a9SChris Wilson 
301ed2690a9SChris Wilson 	/* Check that the delay does not clobber user context state (GPR) */
302ed2690a9SChris Wilson 
303ed2690a9SChris Wilson 	stream = test_stream(&i915->perf);
304ed2690a9SChris Wilson 	if (!stream)
305ed2690a9SChris Wilson 		return -ENOMEM;
306ed2690a9SChris Wilson 
307ed2690a9SChris Wilson 	gpr0 = i915_mmio_reg_offset(GEN8_RING_CS_GPR(stream->engine->mmio_base, 0));
308ed2690a9SChris Wilson 
309ed2690a9SChris Wilson 	ce = intel_context_create(stream->engine);
310ed2690a9SChris Wilson 	if (IS_ERR(ce)) {
311ed2690a9SChris Wilson 		err = PTR_ERR(ce);
312ed2690a9SChris Wilson 		goto out;
313ed2690a9SChris Wilson 	}
314ed2690a9SChris Wilson 
315ed2690a9SChris Wilson 	/* Poison the ce->vm so we detect writes not to the GGTT gt->scratch */
316529b9ec8SMatthew Auld 	scratch = __px_vaddr(ce->vm->scratch[0]);
317ed2690a9SChris Wilson 	memset(scratch, POISON_FREE, PAGE_SIZE);
318ed2690a9SChris Wilson 
319ed2690a9SChris Wilson 	rq = intel_context_create_request(ce);
320ed2690a9SChris Wilson 	if (IS_ERR(rq)) {
321ed2690a9SChris Wilson 		err = PTR_ERR(rq);
322ed2690a9SChris Wilson 		goto out_ce;
323ed2690a9SChris Wilson 	}
324ed2690a9SChris Wilson 	i915_request_get(rq);
325ed2690a9SChris Wilson 
326ed2690a9SChris Wilson 	if (rq->engine->emit_init_breadcrumb) {
327ed2690a9SChris Wilson 		err = rq->engine->emit_init_breadcrumb(rq);
328ed2690a9SChris Wilson 		if (err) {
329ed2690a9SChris Wilson 			i915_request_add(rq);
330ed2690a9SChris Wilson 			goto out_rq;
331ed2690a9SChris Wilson 		}
332ed2690a9SChris Wilson 	}
333ed2690a9SChris Wilson 
334ed2690a9SChris Wilson 	/* Fill the 16 qword [32 dword] GPR with a known unlikely value */
335ed2690a9SChris Wilson 	cs = intel_ring_begin(rq, 2 * 32 + 2);
336ed2690a9SChris Wilson 	if (IS_ERR(cs)) {
337d2921096SColin Ian King 		err = PTR_ERR(cs);
338ed2690a9SChris Wilson 		i915_request_add(rq);
339ed2690a9SChris Wilson 		goto out_rq;
340ed2690a9SChris Wilson 	}
341ed2690a9SChris Wilson 
342ed2690a9SChris Wilson 	*cs++ = MI_LOAD_REGISTER_IMM(32);
343ed2690a9SChris Wilson 	for (i = 0; i < 32; i++) {
344ed2690a9SChris Wilson 		*cs++ = gpr0 + i * sizeof(u32);
345ed2690a9SChris Wilson 		*cs++ = STACK_MAGIC;
346ed2690a9SChris Wilson 	}
347ed2690a9SChris Wilson 	*cs++ = MI_NOOP;
348ed2690a9SChris Wilson 	intel_ring_advance(rq, cs);
349ed2690a9SChris Wilson 
350ed2690a9SChris Wilson 	/* Execute the GPU delay */
351ed2690a9SChris Wilson 	err = rq->engine->emit_bb_start(rq,
352ed2690a9SChris Wilson 					i915_ggtt_offset(stream->noa_wait), 0,
353ed2690a9SChris Wilson 					I915_DISPATCH_SECURE);
354ed2690a9SChris Wilson 	if (err) {
355ed2690a9SChris Wilson 		i915_request_add(rq);
356ed2690a9SChris Wilson 		goto out_rq;
357ed2690a9SChris Wilson 	}
358ed2690a9SChris Wilson 
359ed2690a9SChris Wilson 	/* Read the GPR back, using the pinned global HWSP for convenience */
360ed2690a9SChris Wilson 	store = memset32(rq->engine->status_page.addr + 512, 0, 32);
361ed2690a9SChris Wilson 	for (i = 0; i < 32; i++) {
362ed2690a9SChris Wilson 		u32 cmd;
363ed2690a9SChris Wilson 
364ed2690a9SChris Wilson 		cs = intel_ring_begin(rq, 4);
365ed2690a9SChris Wilson 		if (IS_ERR(cs)) {
36623ec9f42SDan Carpenter 			err = PTR_ERR(cs);
367ed2690a9SChris Wilson 			i915_request_add(rq);
368ed2690a9SChris Wilson 			goto out_rq;
369ed2690a9SChris Wilson 		}
370ed2690a9SChris Wilson 
371ed2690a9SChris Wilson 		cmd = MI_STORE_REGISTER_MEM;
372651e7d48SLucas De Marchi 		if (GRAPHICS_VER(i915) >= 8)
373ed2690a9SChris Wilson 			cmd++;
374ed2690a9SChris Wilson 		cmd |= MI_USE_GGTT;
375ed2690a9SChris Wilson 
376ed2690a9SChris Wilson 		*cs++ = cmd;
377ed2690a9SChris Wilson 		*cs++ = gpr0 + i * sizeof(u32);
378ed2690a9SChris Wilson 		*cs++ = i915_ggtt_offset(rq->engine->status_page.vma) +
379ed2690a9SChris Wilson 			offset_in_page(store) +
380ed2690a9SChris Wilson 			i * sizeof(u32);
381ed2690a9SChris Wilson 		*cs++ = 0;
382ed2690a9SChris Wilson 		intel_ring_advance(rq, cs);
383ed2690a9SChris Wilson 	}
384ed2690a9SChris Wilson 
385ed2690a9SChris Wilson 	i915_request_add(rq);
386ed2690a9SChris Wilson 
387ed2690a9SChris Wilson 	if (i915_request_wait(rq, I915_WAIT_INTERRUPTIBLE, HZ / 2) < 0) {
388ed2690a9SChris Wilson 		pr_err("noa_wait timed out\n");
389ed2690a9SChris Wilson 		intel_gt_set_wedged(stream->engine->gt);
390ed2690a9SChris Wilson 		err = -EIO;
391ed2690a9SChris Wilson 		goto out_rq;
392ed2690a9SChris Wilson 	}
393ed2690a9SChris Wilson 
394ed2690a9SChris Wilson 	/* Verify that the GPR contain our expected values */
395ed2690a9SChris Wilson 	for (i = 0; i < 32; i++) {
396ed2690a9SChris Wilson 		if (store[i] == STACK_MAGIC)
397ed2690a9SChris Wilson 			continue;
398ed2690a9SChris Wilson 
399ed2690a9SChris Wilson 		pr_err("GPR[%d] lost, found:%08x, expected:%08x!\n",
400ed2690a9SChris Wilson 		       i, store[i], STACK_MAGIC);
401ed2690a9SChris Wilson 		err = -EINVAL;
402ed2690a9SChris Wilson 	}
403ed2690a9SChris Wilson 
404ed2690a9SChris Wilson 	/* Verify that the user's scratch page was not used for GPR storage */
405ed2690a9SChris Wilson 	if (memchr_inv(scratch, POISON_FREE, PAGE_SIZE)) {
406ed2690a9SChris Wilson 		pr_err("Scratch page overwritten!\n");
407ed2690a9SChris Wilson 		igt_hexdump(scratch, 4096);
408ed2690a9SChris Wilson 		err = -EINVAL;
409ed2690a9SChris Wilson 	}
410ed2690a9SChris Wilson 
411ed2690a9SChris Wilson out_rq:
412ed2690a9SChris Wilson 	i915_request_put(rq);
413ed2690a9SChris Wilson out_ce:
414ed2690a9SChris Wilson 	intel_context_put(ce);
415ed2690a9SChris Wilson out:
416ed2690a9SChris Wilson 	stream_destroy(stream);
417ed2690a9SChris Wilson 	return err;
418ed2690a9SChris Wilson }
419ed2690a9SChris Wilson 
i915_perf_live_selftests(struct drm_i915_private * i915)420daed3e44SLionel Landwerlin int i915_perf_live_selftests(struct drm_i915_private *i915)
421daed3e44SLionel Landwerlin {
422daed3e44SLionel Landwerlin 	static const struct i915_subtest tests[] = {
423daed3e44SLionel Landwerlin 		SUBTEST(live_sanitycheck),
424daed3e44SLionel Landwerlin 		SUBTEST(live_noa_delay),
425ed2690a9SChris Wilson 		SUBTEST(live_noa_gpr),
426daed3e44SLionel Landwerlin 	};
427daed3e44SLionel Landwerlin 	struct i915_perf *perf = &i915->perf;
4289aba9c18SLionel Landwerlin 	int err;
429daed3e44SLionel Landwerlin 
430daed3e44SLionel Landwerlin 	if (!perf->metrics_kobj || !perf->ops.enable_metric_set)
431daed3e44SLionel Landwerlin 		return 0;
432daed3e44SLionel Landwerlin 
4338c2699faSAndi Shyti 	if (intel_gt_is_wedged(to_gt(i915)))
434daed3e44SLionel Landwerlin 		return 0;
435daed3e44SLionel Landwerlin 
4369aba9c18SLionel Landwerlin 	err = alloc_empty_config(&i915->perf);
4379aba9c18SLionel Landwerlin 	if (err)
4389aba9c18SLionel Landwerlin 		return err;
4399aba9c18SLionel Landwerlin 
44061faec5fSMatthew Brost 	err = i915_live_subtests(tests, i915);
4419aba9c18SLionel Landwerlin 
4429aba9c18SLionel Landwerlin 	destroy_empty_config(&i915->perf);
4439aba9c18SLionel Landwerlin 
4449aba9c18SLionel Landwerlin 	return err;
445daed3e44SLionel Landwerlin }
446