1112ed2d3SChris Wilson /*
2112ed2d3SChris Wilson  * SPDX-License-Identifier: MIT
3112ed2d3SChris Wilson  *
4112ed2d3SChris Wilson  * Copyright © 2018 Intel Corporation
5112ed2d3SChris Wilson  */
6112ed2d3SChris Wilson 
710be98a7SChris Wilson #include "gem/i915_gem_pm.h"
8750e76b4SChris Wilson #include "gt/intel_engine_user.h"
9baea429dSTvrtko Ursulin #include "gt/intel_gt.h"
10112ed2d3SChris Wilson #include "i915_selftest.h"
11112ed2d3SChris Wilson #include "intel_reset.h"
12112ed2d3SChris Wilson 
13112ed2d3SChris Wilson #include "selftests/igt_flush_test.h"
14112ed2d3SChris Wilson #include "selftests/igt_reset.h"
15112ed2d3SChris Wilson #include "selftests/igt_spinner.h"
16112ed2d3SChris Wilson #include "selftests/mock_drm.h"
17112ed2d3SChris Wilson 
1810be98a7SChris Wilson #include "gem/selftests/igt_gem_utils.h"
1910be98a7SChris Wilson #include "gem/selftests/mock_context.h"
2010be98a7SChris Wilson 
21112ed2d3SChris Wilson static const struct wo_register {
22112ed2d3SChris Wilson 	enum intel_platform platform;
23112ed2d3SChris Wilson 	u32 reg;
24112ed2d3SChris Wilson } wo_registers[] = {
25112ed2d3SChris Wilson 	{ INTEL_GEMINILAKE, 0x731c }
26112ed2d3SChris Wilson };
27112ed2d3SChris Wilson 
28112ed2d3SChris Wilson struct wa_lists {
29112ed2d3SChris Wilson 	struct i915_wa_list gt_wa_list;
30112ed2d3SChris Wilson 	struct {
31112ed2d3SChris Wilson 		struct i915_wa_list wa_list;
32fde93886STvrtko Ursulin 		struct i915_wa_list ctx_wa_list;
33112ed2d3SChris Wilson 	} engine[I915_NUM_ENGINES];
34112ed2d3SChris Wilson };
35112ed2d3SChris Wilson 
36112ed2d3SChris Wilson static void
37112ed2d3SChris Wilson reference_lists_init(struct drm_i915_private *i915, struct wa_lists *lists)
38112ed2d3SChris Wilson {
39112ed2d3SChris Wilson 	struct intel_engine_cs *engine;
40112ed2d3SChris Wilson 	enum intel_engine_id id;
41112ed2d3SChris Wilson 
42112ed2d3SChris Wilson 	memset(lists, 0, sizeof(*lists));
43112ed2d3SChris Wilson 
443e1f0a51SJohn Harrison 	wa_init_start(&lists->gt_wa_list, "GT_REF", "global");
45112ed2d3SChris Wilson 	gt_init_workarounds(i915, &lists->gt_wa_list);
46112ed2d3SChris Wilson 	wa_init_finish(&lists->gt_wa_list);
47112ed2d3SChris Wilson 
48112ed2d3SChris Wilson 	for_each_engine(engine, i915, id) {
49112ed2d3SChris Wilson 		struct i915_wa_list *wal = &lists->engine[id].wa_list;
50112ed2d3SChris Wilson 
513e1f0a51SJohn Harrison 		wa_init_start(wal, "REF", engine->name);
52112ed2d3SChris Wilson 		engine_init_workarounds(engine, wal);
53112ed2d3SChris Wilson 		wa_init_finish(wal);
54fde93886STvrtko Ursulin 
55fde93886STvrtko Ursulin 		__intel_engine_init_ctx_wa(engine,
56fde93886STvrtko Ursulin 					   &lists->engine[id].ctx_wa_list,
573e1f0a51SJohn Harrison 					   "CTX_REF");
58112ed2d3SChris Wilson 	}
59112ed2d3SChris Wilson }
60112ed2d3SChris Wilson 
61112ed2d3SChris Wilson static void
62112ed2d3SChris Wilson reference_lists_fini(struct drm_i915_private *i915, struct wa_lists *lists)
63112ed2d3SChris Wilson {
64112ed2d3SChris Wilson 	struct intel_engine_cs *engine;
65112ed2d3SChris Wilson 	enum intel_engine_id id;
66112ed2d3SChris Wilson 
67112ed2d3SChris Wilson 	for_each_engine(engine, i915, id)
68112ed2d3SChris Wilson 		intel_wa_list_free(&lists->engine[id].wa_list);
69112ed2d3SChris Wilson 
70112ed2d3SChris Wilson 	intel_wa_list_free(&lists->gt_wa_list);
71112ed2d3SChris Wilson }
72112ed2d3SChris Wilson 
73112ed2d3SChris Wilson static struct drm_i915_gem_object *
74112ed2d3SChris Wilson read_nonprivs(struct i915_gem_context *ctx, struct intel_engine_cs *engine)
75112ed2d3SChris Wilson {
76112ed2d3SChris Wilson 	const u32 base = engine->mmio_base;
77112ed2d3SChris Wilson 	struct drm_i915_gem_object *result;
78112ed2d3SChris Wilson 	struct i915_request *rq;
79112ed2d3SChris Wilson 	struct i915_vma *vma;
80112ed2d3SChris Wilson 	u32 srm, *cs;
81112ed2d3SChris Wilson 	int err;
82112ed2d3SChris Wilson 	int i;
83112ed2d3SChris Wilson 
84112ed2d3SChris Wilson 	result = i915_gem_object_create_internal(engine->i915, PAGE_SIZE);
85112ed2d3SChris Wilson 	if (IS_ERR(result))
86112ed2d3SChris Wilson 		return result;
87112ed2d3SChris Wilson 
88112ed2d3SChris Wilson 	i915_gem_object_set_cache_coherency(result, I915_CACHE_LLC);
89112ed2d3SChris Wilson 
90112ed2d3SChris Wilson 	cs = i915_gem_object_pin_map(result, I915_MAP_WB);
91112ed2d3SChris Wilson 	if (IS_ERR(cs)) {
92112ed2d3SChris Wilson 		err = PTR_ERR(cs);
93112ed2d3SChris Wilson 		goto err_obj;
94112ed2d3SChris Wilson 	}
95112ed2d3SChris Wilson 	memset(cs, 0xc5, PAGE_SIZE);
96112ed2d3SChris Wilson 	i915_gem_object_flush_map(result);
97112ed2d3SChris Wilson 	i915_gem_object_unpin_map(result);
98112ed2d3SChris Wilson 
99ba4134a4STvrtko Ursulin 	vma = i915_vma_instance(result, &engine->gt->ggtt->vm, NULL);
100112ed2d3SChris Wilson 	if (IS_ERR(vma)) {
101112ed2d3SChris Wilson 		err = PTR_ERR(vma);
102112ed2d3SChris Wilson 		goto err_obj;
103112ed2d3SChris Wilson 	}
104112ed2d3SChris Wilson 
105112ed2d3SChris Wilson 	err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL);
106112ed2d3SChris Wilson 	if (err)
107112ed2d3SChris Wilson 		goto err_obj;
108112ed2d3SChris Wilson 
10946472b3eSChris Wilson 	rq = igt_request_alloc(ctx, engine);
110112ed2d3SChris Wilson 	if (IS_ERR(rq)) {
111112ed2d3SChris Wilson 		err = PTR_ERR(rq);
112112ed2d3SChris Wilson 		goto err_pin;
113112ed2d3SChris Wilson 	}
114112ed2d3SChris Wilson 
1156951e589SChris Wilson 	i915_vma_lock(vma);
11670d6894dSChris Wilson 	err = i915_request_await_object(rq, vma->obj, true);
11770d6894dSChris Wilson 	if (err == 0)
118112ed2d3SChris Wilson 		err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
1196951e589SChris Wilson 	i915_vma_unlock(vma);
120112ed2d3SChris Wilson 	if (err)
121112ed2d3SChris Wilson 		goto err_req;
122112ed2d3SChris Wilson 
123112ed2d3SChris Wilson 	srm = MI_STORE_REGISTER_MEM | MI_SRM_LRM_GLOBAL_GTT;
124112ed2d3SChris Wilson 	if (INTEL_GEN(ctx->i915) >= 8)
125112ed2d3SChris Wilson 		srm++;
126112ed2d3SChris Wilson 
127112ed2d3SChris Wilson 	cs = intel_ring_begin(rq, 4 * RING_MAX_NONPRIV_SLOTS);
128112ed2d3SChris Wilson 	if (IS_ERR(cs)) {
129112ed2d3SChris Wilson 		err = PTR_ERR(cs);
130112ed2d3SChris Wilson 		goto err_req;
131112ed2d3SChris Wilson 	}
132112ed2d3SChris Wilson 
133112ed2d3SChris Wilson 	for (i = 0; i < RING_MAX_NONPRIV_SLOTS; i++) {
134112ed2d3SChris Wilson 		*cs++ = srm;
135112ed2d3SChris Wilson 		*cs++ = i915_mmio_reg_offset(RING_FORCE_TO_NONPRIV(base, i));
136112ed2d3SChris Wilson 		*cs++ = i915_ggtt_offset(vma) + sizeof(u32) * i;
137112ed2d3SChris Wilson 		*cs++ = 0;
138112ed2d3SChris Wilson 	}
139112ed2d3SChris Wilson 	intel_ring_advance(rq, cs);
140112ed2d3SChris Wilson 
141112ed2d3SChris Wilson 	i915_request_add(rq);
142112ed2d3SChris Wilson 	i915_vma_unpin(vma);
143112ed2d3SChris Wilson 
144112ed2d3SChris Wilson 	return result;
145112ed2d3SChris Wilson 
146112ed2d3SChris Wilson err_req:
147112ed2d3SChris Wilson 	i915_request_add(rq);
148112ed2d3SChris Wilson err_pin:
149112ed2d3SChris Wilson 	i915_vma_unpin(vma);
150112ed2d3SChris Wilson err_obj:
151112ed2d3SChris Wilson 	i915_gem_object_put(result);
152112ed2d3SChris Wilson 	return ERR_PTR(err);
153112ed2d3SChris Wilson }
154112ed2d3SChris Wilson 
155112ed2d3SChris Wilson static u32
156112ed2d3SChris Wilson get_whitelist_reg(const struct intel_engine_cs *engine, unsigned int i)
157112ed2d3SChris Wilson {
158112ed2d3SChris Wilson 	i915_reg_t reg = i < engine->whitelist.count ?
159112ed2d3SChris Wilson 			 engine->whitelist.list[i].reg :
160112ed2d3SChris Wilson 			 RING_NOPID(engine->mmio_base);
161112ed2d3SChris Wilson 
162112ed2d3SChris Wilson 	return i915_mmio_reg_offset(reg);
163112ed2d3SChris Wilson }
164112ed2d3SChris Wilson 
165112ed2d3SChris Wilson static void
166112ed2d3SChris Wilson print_results(const struct intel_engine_cs *engine, const u32 *results)
167112ed2d3SChris Wilson {
168112ed2d3SChris Wilson 	unsigned int i;
169112ed2d3SChris Wilson 
170112ed2d3SChris Wilson 	for (i = 0; i < RING_MAX_NONPRIV_SLOTS; i++) {
171112ed2d3SChris Wilson 		u32 expected = get_whitelist_reg(engine, i);
172112ed2d3SChris Wilson 		u32 actual = results[i];
173112ed2d3SChris Wilson 
174112ed2d3SChris Wilson 		pr_info("RING_NONPRIV[%d]: expected 0x%08x, found 0x%08x\n",
175112ed2d3SChris Wilson 			i, expected, actual);
176112ed2d3SChris Wilson 	}
177112ed2d3SChris Wilson }
178112ed2d3SChris Wilson 
179112ed2d3SChris Wilson static int check_whitelist(struct i915_gem_context *ctx,
180112ed2d3SChris Wilson 			   struct intel_engine_cs *engine)
181112ed2d3SChris Wilson {
182112ed2d3SChris Wilson 	struct drm_i915_gem_object *results;
183cb823ed9SChris Wilson 	struct intel_wedge_me wedge;
184112ed2d3SChris Wilson 	u32 *vaddr;
185112ed2d3SChris Wilson 	int err;
186112ed2d3SChris Wilson 	int i;
187112ed2d3SChris Wilson 
188112ed2d3SChris Wilson 	results = read_nonprivs(ctx, engine);
189112ed2d3SChris Wilson 	if (IS_ERR(results))
190112ed2d3SChris Wilson 		return PTR_ERR(results);
191112ed2d3SChris Wilson 
192112ed2d3SChris Wilson 	err = 0;
1936951e589SChris Wilson 	i915_gem_object_lock(results);
194cb823ed9SChris Wilson 	intel_wedge_on_timeout(&wedge, &ctx->i915->gt, HZ / 5) /* safety net! */
195112ed2d3SChris Wilson 		err = i915_gem_object_set_to_cpu_domain(results, false);
1966951e589SChris Wilson 	i915_gem_object_unlock(results);
197cb823ed9SChris Wilson 	if (intel_gt_is_wedged(&ctx->i915->gt))
198112ed2d3SChris Wilson 		err = -EIO;
199112ed2d3SChris Wilson 	if (err)
200112ed2d3SChris Wilson 		goto out_put;
201112ed2d3SChris Wilson 
202112ed2d3SChris Wilson 	vaddr = i915_gem_object_pin_map(results, I915_MAP_WB);
203112ed2d3SChris Wilson 	if (IS_ERR(vaddr)) {
204112ed2d3SChris Wilson 		err = PTR_ERR(vaddr);
205112ed2d3SChris Wilson 		goto out_put;
206112ed2d3SChris Wilson 	}
207112ed2d3SChris Wilson 
208112ed2d3SChris Wilson 	for (i = 0; i < RING_MAX_NONPRIV_SLOTS; i++) {
209112ed2d3SChris Wilson 		u32 expected = get_whitelist_reg(engine, i);
210112ed2d3SChris Wilson 		u32 actual = vaddr[i];
211112ed2d3SChris Wilson 
212112ed2d3SChris Wilson 		if (expected != actual) {
213112ed2d3SChris Wilson 			print_results(engine, vaddr);
214112ed2d3SChris Wilson 			pr_err("Invalid RING_NONPRIV[%d], expected 0x%08x, found 0x%08x\n",
215112ed2d3SChris Wilson 			       i, expected, actual);
216112ed2d3SChris Wilson 
217112ed2d3SChris Wilson 			err = -EINVAL;
218112ed2d3SChris Wilson 			break;
219112ed2d3SChris Wilson 		}
220112ed2d3SChris Wilson 	}
221112ed2d3SChris Wilson 
222112ed2d3SChris Wilson 	i915_gem_object_unpin_map(results);
223112ed2d3SChris Wilson out_put:
224112ed2d3SChris Wilson 	i915_gem_object_put(results);
225112ed2d3SChris Wilson 	return err;
226112ed2d3SChris Wilson }
227112ed2d3SChris Wilson 
228112ed2d3SChris Wilson static int do_device_reset(struct intel_engine_cs *engine)
229112ed2d3SChris Wilson {
230cb823ed9SChris Wilson 	intel_gt_reset(engine->gt, engine->mask, "live_workarounds");
231112ed2d3SChris Wilson 	return 0;
232112ed2d3SChris Wilson }
233112ed2d3SChris Wilson 
234112ed2d3SChris Wilson static int do_engine_reset(struct intel_engine_cs *engine)
235112ed2d3SChris Wilson {
236cb823ed9SChris Wilson 	return intel_engine_reset(engine, "live_workarounds");
237112ed2d3SChris Wilson }
238112ed2d3SChris Wilson 
239112ed2d3SChris Wilson static int
240112ed2d3SChris Wilson switch_to_scratch_context(struct intel_engine_cs *engine,
241112ed2d3SChris Wilson 			  struct igt_spinner *spin)
242112ed2d3SChris Wilson {
243112ed2d3SChris Wilson 	struct i915_gem_context *ctx;
244f277bc0cSChris Wilson 	struct intel_context *ce;
245112ed2d3SChris Wilson 	struct i915_request *rq;
246112ed2d3SChris Wilson 	intel_wakeref_t wakeref;
247112ed2d3SChris Wilson 	int err = 0;
248112ed2d3SChris Wilson 
249112ed2d3SChris Wilson 	ctx = kernel_context(engine->i915);
250112ed2d3SChris Wilson 	if (IS_ERR(ctx))
251112ed2d3SChris Wilson 		return PTR_ERR(ctx);
252112ed2d3SChris Wilson 
253112ed2d3SChris Wilson 	GEM_BUG_ON(i915_gem_context_is_bannable(ctx));
254112ed2d3SChris Wilson 
255f1c4d157SChris Wilson 	ce = i915_gem_context_get_engine(ctx, engine->legacy_idx);
256f277bc0cSChris Wilson 	GEM_BUG_ON(IS_ERR(ce));
257f277bc0cSChris Wilson 
258112ed2d3SChris Wilson 	rq = ERR_PTR(-ENODEV);
259c447ff7dSDaniele Ceraolo Spurio 	with_intel_runtime_pm(&engine->i915->runtime_pm, wakeref)
260f277bc0cSChris Wilson 		rq = igt_spinner_create_request(spin, ce, MI_NOOP);
261112ed2d3SChris Wilson 
262f277bc0cSChris Wilson 	intel_context_put(ce);
263112ed2d3SChris Wilson 	kernel_context_close(ctx);
264112ed2d3SChris Wilson 
265112ed2d3SChris Wilson 	if (IS_ERR(rq)) {
266112ed2d3SChris Wilson 		spin = NULL;
267112ed2d3SChris Wilson 		err = PTR_ERR(rq);
268112ed2d3SChris Wilson 		goto err;
269112ed2d3SChris Wilson 	}
270112ed2d3SChris Wilson 
271112ed2d3SChris Wilson 	i915_request_add(rq);
272112ed2d3SChris Wilson 
273112ed2d3SChris Wilson 	if (spin && !igt_wait_for_spinner(spin, rq)) {
274112ed2d3SChris Wilson 		pr_err("Spinner failed to start\n");
275112ed2d3SChris Wilson 		err = -ETIMEDOUT;
276112ed2d3SChris Wilson 	}
277112ed2d3SChris Wilson 
278112ed2d3SChris Wilson err:
279112ed2d3SChris Wilson 	if (err && spin)
280112ed2d3SChris Wilson 		igt_spinner_end(spin);
281112ed2d3SChris Wilson 
282112ed2d3SChris Wilson 	return err;
283112ed2d3SChris Wilson }
284112ed2d3SChris Wilson 
285112ed2d3SChris Wilson static int check_whitelist_across_reset(struct intel_engine_cs *engine,
286112ed2d3SChris Wilson 					int (*reset)(struct intel_engine_cs *),
287112ed2d3SChris Wilson 					const char *name)
288112ed2d3SChris Wilson {
289112ed2d3SChris Wilson 	struct drm_i915_private *i915 = engine->i915;
290cf3bd1a0SChris Wilson 	struct i915_gem_context *ctx, *tmp;
291112ed2d3SChris Wilson 	struct igt_spinner spin;
292112ed2d3SChris Wilson 	intel_wakeref_t wakeref;
293112ed2d3SChris Wilson 	int err;
294112ed2d3SChris Wilson 
2953e1f0a51SJohn Harrison 	pr_info("Checking %d whitelisted registers on %s (RING_NONPRIV) [%s]\n",
2963e1f0a51SJohn Harrison 		engine->whitelist.count, engine->name, name);
297112ed2d3SChris Wilson 
298112ed2d3SChris Wilson 	ctx = kernel_context(i915);
299112ed2d3SChris Wilson 	if (IS_ERR(ctx))
300112ed2d3SChris Wilson 		return PTR_ERR(ctx);
301112ed2d3SChris Wilson 
302f277bc0cSChris Wilson 	err = igt_spinner_init(&spin, engine->gt);
303cf3bd1a0SChris Wilson 	if (err)
304cf3bd1a0SChris Wilson 		goto out_ctx;
305cf3bd1a0SChris Wilson 
306112ed2d3SChris Wilson 	err = check_whitelist(ctx, engine);
307112ed2d3SChris Wilson 	if (err) {
308112ed2d3SChris Wilson 		pr_err("Invalid whitelist *before* %s reset!\n", name);
309cf3bd1a0SChris Wilson 		goto out_spin;
310112ed2d3SChris Wilson 	}
311112ed2d3SChris Wilson 
312112ed2d3SChris Wilson 	err = switch_to_scratch_context(engine, &spin);
313112ed2d3SChris Wilson 	if (err)
314cf3bd1a0SChris Wilson 		goto out_spin;
315112ed2d3SChris Wilson 
316c447ff7dSDaniele Ceraolo Spurio 	with_intel_runtime_pm(&i915->runtime_pm, wakeref)
317112ed2d3SChris Wilson 		err = reset(engine);
318112ed2d3SChris Wilson 
319112ed2d3SChris Wilson 	igt_spinner_end(&spin);
320112ed2d3SChris Wilson 
321112ed2d3SChris Wilson 	if (err) {
322112ed2d3SChris Wilson 		pr_err("%s reset failed\n", name);
323cf3bd1a0SChris Wilson 		goto out_spin;
324112ed2d3SChris Wilson 	}
325112ed2d3SChris Wilson 
326112ed2d3SChris Wilson 	err = check_whitelist(ctx, engine);
327112ed2d3SChris Wilson 	if (err) {
328112ed2d3SChris Wilson 		pr_err("Whitelist not preserved in context across %s reset!\n",
329112ed2d3SChris Wilson 		       name);
330cf3bd1a0SChris Wilson 		goto out_spin;
331112ed2d3SChris Wilson 	}
332112ed2d3SChris Wilson 
333cf3bd1a0SChris Wilson 	tmp = kernel_context(i915);
334cf3bd1a0SChris Wilson 	if (IS_ERR(tmp)) {
335cf3bd1a0SChris Wilson 		err = PTR_ERR(tmp);
336cf3bd1a0SChris Wilson 		goto out_spin;
337cf3bd1a0SChris Wilson 	}
338112ed2d3SChris Wilson 	kernel_context_close(ctx);
339cf3bd1a0SChris Wilson 	ctx = tmp;
340112ed2d3SChris Wilson 
341112ed2d3SChris Wilson 	err = check_whitelist(ctx, engine);
342112ed2d3SChris Wilson 	if (err) {
343112ed2d3SChris Wilson 		pr_err("Invalid whitelist *after* %s reset in fresh context!\n",
344112ed2d3SChris Wilson 		       name);
345cf3bd1a0SChris Wilson 		goto out_spin;
346112ed2d3SChris Wilson 	}
347112ed2d3SChris Wilson 
348cf3bd1a0SChris Wilson out_spin:
349cf3bd1a0SChris Wilson 	igt_spinner_fini(&spin);
350cf3bd1a0SChris Wilson out_ctx:
351112ed2d3SChris Wilson 	kernel_context_close(ctx);
352112ed2d3SChris Wilson 	return err;
353112ed2d3SChris Wilson }
354112ed2d3SChris Wilson 
355112ed2d3SChris Wilson static struct i915_vma *create_batch(struct i915_gem_context *ctx)
356112ed2d3SChris Wilson {
357112ed2d3SChris Wilson 	struct drm_i915_gem_object *obj;
358112ed2d3SChris Wilson 	struct i915_vma *vma;
359112ed2d3SChris Wilson 	int err;
360112ed2d3SChris Wilson 
361112ed2d3SChris Wilson 	obj = i915_gem_object_create_internal(ctx->i915, 16 * PAGE_SIZE);
362112ed2d3SChris Wilson 	if (IS_ERR(obj))
363112ed2d3SChris Wilson 		return ERR_CAST(obj);
364112ed2d3SChris Wilson 
365e568ac38SChris Wilson 	vma = i915_vma_instance(obj, ctx->vm, NULL);
366112ed2d3SChris Wilson 	if (IS_ERR(vma)) {
367112ed2d3SChris Wilson 		err = PTR_ERR(vma);
368112ed2d3SChris Wilson 		goto err_obj;
369112ed2d3SChris Wilson 	}
370112ed2d3SChris Wilson 
371112ed2d3SChris Wilson 	err = i915_vma_pin(vma, 0, 0, PIN_USER);
372112ed2d3SChris Wilson 	if (err)
373112ed2d3SChris Wilson 		goto err_obj;
374112ed2d3SChris Wilson 
375112ed2d3SChris Wilson 	return vma;
376112ed2d3SChris Wilson 
377112ed2d3SChris Wilson err_obj:
378112ed2d3SChris Wilson 	i915_gem_object_put(obj);
379112ed2d3SChris Wilson 	return ERR_PTR(err);
380112ed2d3SChris Wilson }
381112ed2d3SChris Wilson 
382112ed2d3SChris Wilson static u32 reg_write(u32 old, u32 new, u32 rsvd)
383112ed2d3SChris Wilson {
384112ed2d3SChris Wilson 	if (rsvd == 0x0000ffff) {
385112ed2d3SChris Wilson 		old &= ~(new >> 16);
386112ed2d3SChris Wilson 		old |= new & (new >> 16);
387112ed2d3SChris Wilson 	} else {
388112ed2d3SChris Wilson 		old &= ~rsvd;
389112ed2d3SChris Wilson 		old |= new & rsvd;
390112ed2d3SChris Wilson 	}
391112ed2d3SChris Wilson 
392112ed2d3SChris Wilson 	return old;
393112ed2d3SChris Wilson }
394112ed2d3SChris Wilson 
395112ed2d3SChris Wilson static bool wo_register(struct intel_engine_cs *engine, u32 reg)
396112ed2d3SChris Wilson {
397112ed2d3SChris Wilson 	enum intel_platform platform = INTEL_INFO(engine->i915)->platform;
398112ed2d3SChris Wilson 	int i;
399112ed2d3SChris Wilson 
4001e2b7f49SJohn Harrison 	if ((reg & RING_FORCE_TO_NONPRIV_ACCESS_MASK) ==
4011e2b7f49SJohn Harrison 	     RING_FORCE_TO_NONPRIV_ACCESS_WR)
4021e2b7f49SJohn Harrison 		return true;
4031e2b7f49SJohn Harrison 
404112ed2d3SChris Wilson 	for (i = 0; i < ARRAY_SIZE(wo_registers); i++) {
405112ed2d3SChris Wilson 		if (wo_registers[i].platform == platform &&
406112ed2d3SChris Wilson 		    wo_registers[i].reg == reg)
407112ed2d3SChris Wilson 			return true;
408112ed2d3SChris Wilson 	}
409112ed2d3SChris Wilson 
410112ed2d3SChris Wilson 	return false;
411112ed2d3SChris Wilson }
412112ed2d3SChris Wilson 
413767662bcSRobert M. Fosha static bool ro_register(u32 reg)
414767662bcSRobert M. Fosha {
4151e2b7f49SJohn Harrison 	if ((reg & RING_FORCE_TO_NONPRIV_ACCESS_MASK) ==
4161e2b7f49SJohn Harrison 	     RING_FORCE_TO_NONPRIV_ACCESS_RD)
417767662bcSRobert M. Fosha 		return true;
418767662bcSRobert M. Fosha 
419767662bcSRobert M. Fosha 	return false;
420767662bcSRobert M. Fosha }
421767662bcSRobert M. Fosha 
422767662bcSRobert M. Fosha static int whitelist_writable_count(struct intel_engine_cs *engine)
423767662bcSRobert M. Fosha {
424767662bcSRobert M. Fosha 	int count = engine->whitelist.count;
425767662bcSRobert M. Fosha 	int i;
426767662bcSRobert M. Fosha 
427767662bcSRobert M. Fosha 	for (i = 0; i < engine->whitelist.count; i++) {
428767662bcSRobert M. Fosha 		u32 reg = i915_mmio_reg_offset(engine->whitelist.list[i].reg);
429767662bcSRobert M. Fosha 
430767662bcSRobert M. Fosha 		if (ro_register(reg))
431767662bcSRobert M. Fosha 			count--;
432767662bcSRobert M. Fosha 	}
433767662bcSRobert M. Fosha 
434767662bcSRobert M. Fosha 	return count;
435767662bcSRobert M. Fosha }
436767662bcSRobert M. Fosha 
437112ed2d3SChris Wilson static int check_dirty_whitelist(struct i915_gem_context *ctx,
438112ed2d3SChris Wilson 				 struct intel_engine_cs *engine)
439112ed2d3SChris Wilson {
440112ed2d3SChris Wilson 	const u32 values[] = {
441112ed2d3SChris Wilson 		0x00000000,
442112ed2d3SChris Wilson 		0x01010101,
443112ed2d3SChris Wilson 		0x10100101,
444112ed2d3SChris Wilson 		0x03030303,
445112ed2d3SChris Wilson 		0x30300303,
446112ed2d3SChris Wilson 		0x05050505,
447112ed2d3SChris Wilson 		0x50500505,
448112ed2d3SChris Wilson 		0x0f0f0f0f,
449112ed2d3SChris Wilson 		0xf00ff00f,
450112ed2d3SChris Wilson 		0x10101010,
451112ed2d3SChris Wilson 		0xf0f01010,
452112ed2d3SChris Wilson 		0x30303030,
453112ed2d3SChris Wilson 		0xa0a03030,
454112ed2d3SChris Wilson 		0x50505050,
455112ed2d3SChris Wilson 		0xc0c05050,
456112ed2d3SChris Wilson 		0xf0f0f0f0,
457112ed2d3SChris Wilson 		0x11111111,
458112ed2d3SChris Wilson 		0x33333333,
459112ed2d3SChris Wilson 		0x55555555,
460112ed2d3SChris Wilson 		0x0000ffff,
461112ed2d3SChris Wilson 		0x00ff00ff,
462112ed2d3SChris Wilson 		0xff0000ff,
463112ed2d3SChris Wilson 		0xffff00ff,
464112ed2d3SChris Wilson 		0xffffffff,
465112ed2d3SChris Wilson 	};
466112ed2d3SChris Wilson 	struct i915_vma *scratch;
467112ed2d3SChris Wilson 	struct i915_vma *batch;
468112ed2d3SChris Wilson 	int err = 0, i, v;
469112ed2d3SChris Wilson 	u32 *cs, *results;
470112ed2d3SChris Wilson 
471e568ac38SChris Wilson 	scratch = create_scratch(ctx->vm, 2 * ARRAY_SIZE(values) + 1);
472112ed2d3SChris Wilson 	if (IS_ERR(scratch))
473112ed2d3SChris Wilson 		return PTR_ERR(scratch);
474112ed2d3SChris Wilson 
475112ed2d3SChris Wilson 	batch = create_batch(ctx);
476112ed2d3SChris Wilson 	if (IS_ERR(batch)) {
477112ed2d3SChris Wilson 		err = PTR_ERR(batch);
478112ed2d3SChris Wilson 		goto out_scratch;
479112ed2d3SChris Wilson 	}
480112ed2d3SChris Wilson 
481112ed2d3SChris Wilson 	for (i = 0; i < engine->whitelist.count; i++) {
482112ed2d3SChris Wilson 		u32 reg = i915_mmio_reg_offset(engine->whitelist.list[i].reg);
483112ed2d3SChris Wilson 		u64 addr = scratch->node.start;
484112ed2d3SChris Wilson 		struct i915_request *rq;
485112ed2d3SChris Wilson 		u32 srm, lrm, rsvd;
486112ed2d3SChris Wilson 		u32 expect;
487112ed2d3SChris Wilson 		int idx;
488aee20aaeSJohn Harrison 		bool ro_reg;
489112ed2d3SChris Wilson 
490112ed2d3SChris Wilson 		if (wo_register(engine, reg))
491112ed2d3SChris Wilson 			continue;
492112ed2d3SChris Wilson 
493aee20aaeSJohn Harrison 		ro_reg = ro_register(reg);
494767662bcSRobert M. Fosha 
495112ed2d3SChris Wilson 		srm = MI_STORE_REGISTER_MEM;
496112ed2d3SChris Wilson 		lrm = MI_LOAD_REGISTER_MEM;
497112ed2d3SChris Wilson 		if (INTEL_GEN(ctx->i915) >= 8)
498112ed2d3SChris Wilson 			lrm++, srm++;
499112ed2d3SChris Wilson 
500112ed2d3SChris Wilson 		pr_debug("%s: Writing garbage to %x\n",
501112ed2d3SChris Wilson 			 engine->name, reg);
502112ed2d3SChris Wilson 
503112ed2d3SChris Wilson 		cs = i915_gem_object_pin_map(batch->obj, I915_MAP_WC);
504112ed2d3SChris Wilson 		if (IS_ERR(cs)) {
505112ed2d3SChris Wilson 			err = PTR_ERR(cs);
506112ed2d3SChris Wilson 			goto out_batch;
507112ed2d3SChris Wilson 		}
508112ed2d3SChris Wilson 
509112ed2d3SChris Wilson 		/* SRM original */
510112ed2d3SChris Wilson 		*cs++ = srm;
511112ed2d3SChris Wilson 		*cs++ = reg;
512112ed2d3SChris Wilson 		*cs++ = lower_32_bits(addr);
513112ed2d3SChris Wilson 		*cs++ = upper_32_bits(addr);
514112ed2d3SChris Wilson 
515112ed2d3SChris Wilson 		idx = 1;
516112ed2d3SChris Wilson 		for (v = 0; v < ARRAY_SIZE(values); v++) {
517112ed2d3SChris Wilson 			/* LRI garbage */
518112ed2d3SChris Wilson 			*cs++ = MI_LOAD_REGISTER_IMM(1);
519112ed2d3SChris Wilson 			*cs++ = reg;
520112ed2d3SChris Wilson 			*cs++ = values[v];
521112ed2d3SChris Wilson 
522112ed2d3SChris Wilson 			/* SRM result */
523112ed2d3SChris Wilson 			*cs++ = srm;
524112ed2d3SChris Wilson 			*cs++ = reg;
525112ed2d3SChris Wilson 			*cs++ = lower_32_bits(addr + sizeof(u32) * idx);
526112ed2d3SChris Wilson 			*cs++ = upper_32_bits(addr + sizeof(u32) * idx);
527112ed2d3SChris Wilson 			idx++;
528112ed2d3SChris Wilson 		}
529112ed2d3SChris Wilson 		for (v = 0; v < ARRAY_SIZE(values); v++) {
530112ed2d3SChris Wilson 			/* LRI garbage */
531112ed2d3SChris Wilson 			*cs++ = MI_LOAD_REGISTER_IMM(1);
532112ed2d3SChris Wilson 			*cs++ = reg;
533112ed2d3SChris Wilson 			*cs++ = ~values[v];
534112ed2d3SChris Wilson 
535112ed2d3SChris Wilson 			/* SRM result */
536112ed2d3SChris Wilson 			*cs++ = srm;
537112ed2d3SChris Wilson 			*cs++ = reg;
538112ed2d3SChris Wilson 			*cs++ = lower_32_bits(addr + sizeof(u32) * idx);
539112ed2d3SChris Wilson 			*cs++ = upper_32_bits(addr + sizeof(u32) * idx);
540112ed2d3SChris Wilson 			idx++;
541112ed2d3SChris Wilson 		}
542112ed2d3SChris Wilson 		GEM_BUG_ON(idx * sizeof(u32) > scratch->size);
543112ed2d3SChris Wilson 
544112ed2d3SChris Wilson 		/* LRM original -- don't leave garbage in the context! */
545112ed2d3SChris Wilson 		*cs++ = lrm;
546112ed2d3SChris Wilson 		*cs++ = reg;
547112ed2d3SChris Wilson 		*cs++ = lower_32_bits(addr);
548112ed2d3SChris Wilson 		*cs++ = upper_32_bits(addr);
549112ed2d3SChris Wilson 
550112ed2d3SChris Wilson 		*cs++ = MI_BATCH_BUFFER_END;
551112ed2d3SChris Wilson 
552112ed2d3SChris Wilson 		i915_gem_object_flush_map(batch->obj);
553112ed2d3SChris Wilson 		i915_gem_object_unpin_map(batch->obj);
554baea429dSTvrtko Ursulin 		intel_gt_chipset_flush(engine->gt);
555112ed2d3SChris Wilson 
55646472b3eSChris Wilson 		rq = igt_request_alloc(ctx, engine);
557112ed2d3SChris Wilson 		if (IS_ERR(rq)) {
558112ed2d3SChris Wilson 			err = PTR_ERR(rq);
559112ed2d3SChris Wilson 			goto out_batch;
560112ed2d3SChris Wilson 		}
561112ed2d3SChris Wilson 
562112ed2d3SChris Wilson 		if (engine->emit_init_breadcrumb) { /* Be nice if we hang */
563112ed2d3SChris Wilson 			err = engine->emit_init_breadcrumb(rq);
564112ed2d3SChris Wilson 			if (err)
565112ed2d3SChris Wilson 				goto err_request;
566112ed2d3SChris Wilson 		}
567112ed2d3SChris Wilson 
5681d5b7773SChris Wilson 		i915_vma_lock(batch);
5691d5b7773SChris Wilson 		err = i915_request_await_object(rq, batch->obj, false);
5701d5b7773SChris Wilson 		if (err == 0)
5711d5b7773SChris Wilson 			err = i915_vma_move_to_active(batch, rq, 0);
5721d5b7773SChris Wilson 		i915_vma_unlock(batch);
5731d5b7773SChris Wilson 		if (err)
5741d5b7773SChris Wilson 			goto err_request;
5751d5b7773SChris Wilson 
576112ed2d3SChris Wilson 		err = engine->emit_bb_start(rq,
577112ed2d3SChris Wilson 					    batch->node.start, PAGE_SIZE,
578112ed2d3SChris Wilson 					    0);
579112ed2d3SChris Wilson 		if (err)
580112ed2d3SChris Wilson 			goto err_request;
581112ed2d3SChris Wilson 
582112ed2d3SChris Wilson err_request:
583112ed2d3SChris Wilson 		i915_request_add(rq);
584112ed2d3SChris Wilson 		if (err)
585112ed2d3SChris Wilson 			goto out_batch;
586112ed2d3SChris Wilson 
5872f530945SChris Wilson 		if (i915_request_wait(rq, 0, HZ / 5) < 0) {
588112ed2d3SChris Wilson 			pr_err("%s: Futzing %x timedout; cancelling test\n",
589112ed2d3SChris Wilson 			       engine->name, reg);
590cb823ed9SChris Wilson 			intel_gt_set_wedged(&ctx->i915->gt);
591112ed2d3SChris Wilson 			err = -EIO;
592112ed2d3SChris Wilson 			goto out_batch;
593112ed2d3SChris Wilson 		}
594112ed2d3SChris Wilson 
595112ed2d3SChris Wilson 		results = i915_gem_object_pin_map(scratch->obj, I915_MAP_WB);
596112ed2d3SChris Wilson 		if (IS_ERR(results)) {
597112ed2d3SChris Wilson 			err = PTR_ERR(results);
598112ed2d3SChris Wilson 			goto out_batch;
599112ed2d3SChris Wilson 		}
600112ed2d3SChris Wilson 
601112ed2d3SChris Wilson 		GEM_BUG_ON(values[ARRAY_SIZE(values) - 1] != 0xffffffff);
602aee20aaeSJohn Harrison 		if (!ro_reg) {
603aee20aaeSJohn Harrison 			/* detect write masking */
604aee20aaeSJohn Harrison 			rsvd = results[ARRAY_SIZE(values)];
605112ed2d3SChris Wilson 			if (!rsvd) {
606112ed2d3SChris Wilson 				pr_err("%s: Unable to write to whitelisted register %x\n",
607112ed2d3SChris Wilson 				       engine->name, reg);
608112ed2d3SChris Wilson 				err = -EINVAL;
609112ed2d3SChris Wilson 				goto out_unpin;
610112ed2d3SChris Wilson 			}
611aee20aaeSJohn Harrison 		}
612112ed2d3SChris Wilson 
613112ed2d3SChris Wilson 		expect = results[0];
614112ed2d3SChris Wilson 		idx = 1;
615112ed2d3SChris Wilson 		for (v = 0; v < ARRAY_SIZE(values); v++) {
616aee20aaeSJohn Harrison 			if (ro_reg)
617aee20aaeSJohn Harrison 				expect = results[0];
618aee20aaeSJohn Harrison 			else
619112ed2d3SChris Wilson 				expect = reg_write(expect, values[v], rsvd);
620aee20aaeSJohn Harrison 
621112ed2d3SChris Wilson 			if (results[idx] != expect)
622112ed2d3SChris Wilson 				err++;
623112ed2d3SChris Wilson 			idx++;
624112ed2d3SChris Wilson 		}
625112ed2d3SChris Wilson 		for (v = 0; v < ARRAY_SIZE(values); v++) {
626aee20aaeSJohn Harrison 			if (ro_reg)
627aee20aaeSJohn Harrison 				expect = results[0];
628aee20aaeSJohn Harrison 			else
629112ed2d3SChris Wilson 				expect = reg_write(expect, ~values[v], rsvd);
630aee20aaeSJohn Harrison 
631112ed2d3SChris Wilson 			if (results[idx] != expect)
632112ed2d3SChris Wilson 				err++;
633112ed2d3SChris Wilson 			idx++;
634112ed2d3SChris Wilson 		}
635112ed2d3SChris Wilson 		if (err) {
636112ed2d3SChris Wilson 			pr_err("%s: %d mismatch between values written to whitelisted register [%x], and values read back!\n",
637112ed2d3SChris Wilson 			       engine->name, err, reg);
638112ed2d3SChris Wilson 
639aee20aaeSJohn Harrison 			if (ro_reg)
640aee20aaeSJohn Harrison 				pr_info("%s: Whitelisted read-only register: %x, original value %08x\n",
641aee20aaeSJohn Harrison 					engine->name, reg, results[0]);
642aee20aaeSJohn Harrison 			else
643112ed2d3SChris Wilson 				pr_info("%s: Whitelisted register: %x, original value %08x, rsvd %08x\n",
644112ed2d3SChris Wilson 					engine->name, reg, results[0], rsvd);
645112ed2d3SChris Wilson 
646112ed2d3SChris Wilson 			expect = results[0];
647112ed2d3SChris Wilson 			idx = 1;
648112ed2d3SChris Wilson 			for (v = 0; v < ARRAY_SIZE(values); v++) {
649112ed2d3SChris Wilson 				u32 w = values[v];
650112ed2d3SChris Wilson 
651aee20aaeSJohn Harrison 				if (ro_reg)
652aee20aaeSJohn Harrison 					expect = results[0];
653aee20aaeSJohn Harrison 				else
654112ed2d3SChris Wilson 					expect = reg_write(expect, w, rsvd);
655112ed2d3SChris Wilson 				pr_info("Wrote %08x, read %08x, expect %08x\n",
656112ed2d3SChris Wilson 					w, results[idx], expect);
657112ed2d3SChris Wilson 				idx++;
658112ed2d3SChris Wilson 			}
659112ed2d3SChris Wilson 			for (v = 0; v < ARRAY_SIZE(values); v++) {
660112ed2d3SChris Wilson 				u32 w = ~values[v];
661112ed2d3SChris Wilson 
662aee20aaeSJohn Harrison 				if (ro_reg)
663aee20aaeSJohn Harrison 					expect = results[0];
664aee20aaeSJohn Harrison 				else
665112ed2d3SChris Wilson 					expect = reg_write(expect, w, rsvd);
666112ed2d3SChris Wilson 				pr_info("Wrote %08x, read %08x, expect %08x\n",
667112ed2d3SChris Wilson 					w, results[idx], expect);
668112ed2d3SChris Wilson 				idx++;
669112ed2d3SChris Wilson 			}
670112ed2d3SChris Wilson 
671112ed2d3SChris Wilson 			err = -EINVAL;
672112ed2d3SChris Wilson 		}
673112ed2d3SChris Wilson out_unpin:
674112ed2d3SChris Wilson 		i915_gem_object_unpin_map(scratch->obj);
675112ed2d3SChris Wilson 		if (err)
676112ed2d3SChris Wilson 			break;
677112ed2d3SChris Wilson 	}
678112ed2d3SChris Wilson 
679112ed2d3SChris Wilson 	if (igt_flush_test(ctx->i915, I915_WAIT_LOCKED))
680112ed2d3SChris Wilson 		err = -EIO;
681112ed2d3SChris Wilson out_batch:
682112ed2d3SChris Wilson 	i915_vma_unpin_and_release(&batch, 0);
683112ed2d3SChris Wilson out_scratch:
684112ed2d3SChris Wilson 	i915_vma_unpin_and_release(&scratch, 0);
685112ed2d3SChris Wilson 	return err;
686112ed2d3SChris Wilson }
687112ed2d3SChris Wilson 
688112ed2d3SChris Wilson static int live_dirty_whitelist(void *arg)
689112ed2d3SChris Wilson {
690112ed2d3SChris Wilson 	struct drm_i915_private *i915 = arg;
691112ed2d3SChris Wilson 	struct intel_engine_cs *engine;
692112ed2d3SChris Wilson 	struct i915_gem_context *ctx;
693112ed2d3SChris Wilson 	enum intel_engine_id id;
694112ed2d3SChris Wilson 	intel_wakeref_t wakeref;
695112ed2d3SChris Wilson 	struct drm_file *file;
696112ed2d3SChris Wilson 	int err = 0;
697112ed2d3SChris Wilson 
698112ed2d3SChris Wilson 	/* Can the user write to the whitelisted registers? */
699112ed2d3SChris Wilson 
700112ed2d3SChris Wilson 	if (INTEL_GEN(i915) < 7) /* minimum requirement for LRI, SRM, LRM */
701112ed2d3SChris Wilson 		return 0;
702112ed2d3SChris Wilson 
703d858d569SDaniele Ceraolo Spurio 	wakeref = intel_runtime_pm_get(&i915->runtime_pm);
704112ed2d3SChris Wilson 
705112ed2d3SChris Wilson 	mutex_unlock(&i915->drm.struct_mutex);
706112ed2d3SChris Wilson 	file = mock_file(i915);
707112ed2d3SChris Wilson 	mutex_lock(&i915->drm.struct_mutex);
708112ed2d3SChris Wilson 	if (IS_ERR(file)) {
709112ed2d3SChris Wilson 		err = PTR_ERR(file);
710112ed2d3SChris Wilson 		goto out_rpm;
711112ed2d3SChris Wilson 	}
712112ed2d3SChris Wilson 
713112ed2d3SChris Wilson 	ctx = live_context(i915, file);
714112ed2d3SChris Wilson 	if (IS_ERR(ctx)) {
715112ed2d3SChris Wilson 		err = PTR_ERR(ctx);
716112ed2d3SChris Wilson 		goto out_file;
717112ed2d3SChris Wilson 	}
718112ed2d3SChris Wilson 
719112ed2d3SChris Wilson 	for_each_engine(engine, i915, id) {
720112ed2d3SChris Wilson 		if (engine->whitelist.count == 0)
721112ed2d3SChris Wilson 			continue;
722112ed2d3SChris Wilson 
723112ed2d3SChris Wilson 		err = check_dirty_whitelist(ctx, engine);
724112ed2d3SChris Wilson 		if (err)
725112ed2d3SChris Wilson 			goto out_file;
726112ed2d3SChris Wilson 	}
727112ed2d3SChris Wilson 
728112ed2d3SChris Wilson out_file:
729112ed2d3SChris Wilson 	mutex_unlock(&i915->drm.struct_mutex);
730112ed2d3SChris Wilson 	mock_file_free(i915, file);
731112ed2d3SChris Wilson 	mutex_lock(&i915->drm.struct_mutex);
732112ed2d3SChris Wilson out_rpm:
733d858d569SDaniele Ceraolo Spurio 	intel_runtime_pm_put(&i915->runtime_pm, wakeref);
734112ed2d3SChris Wilson 	return err;
735112ed2d3SChris Wilson }
736112ed2d3SChris Wilson 
737112ed2d3SChris Wilson static int live_reset_whitelist(void *arg)
738112ed2d3SChris Wilson {
739112ed2d3SChris Wilson 	struct drm_i915_private *i915 = arg;
740112ed2d3SChris Wilson 	struct intel_engine_cs *engine = i915->engine[RCS0];
741112ed2d3SChris Wilson 	int err = 0;
742112ed2d3SChris Wilson 
743112ed2d3SChris Wilson 	/* If we reset the gpu, we should not lose the RING_NONPRIV */
744112ed2d3SChris Wilson 
745112ed2d3SChris Wilson 	if (!engine || engine->whitelist.count == 0)
746112ed2d3SChris Wilson 		return 0;
747112ed2d3SChris Wilson 
748cb823ed9SChris Wilson 	igt_global_reset_lock(&i915->gt);
749112ed2d3SChris Wilson 
750112ed2d3SChris Wilson 	if (intel_has_reset_engine(i915)) {
751112ed2d3SChris Wilson 		err = check_whitelist_across_reset(engine,
752112ed2d3SChris Wilson 						   do_engine_reset,
753112ed2d3SChris Wilson 						   "engine");
754112ed2d3SChris Wilson 		if (err)
755112ed2d3SChris Wilson 			goto out;
756112ed2d3SChris Wilson 	}
757112ed2d3SChris Wilson 
758112ed2d3SChris Wilson 	if (intel_has_gpu_reset(i915)) {
759112ed2d3SChris Wilson 		err = check_whitelist_across_reset(engine,
760112ed2d3SChris Wilson 						   do_device_reset,
761112ed2d3SChris Wilson 						   "device");
762112ed2d3SChris Wilson 		if (err)
763112ed2d3SChris Wilson 			goto out;
764112ed2d3SChris Wilson 	}
765112ed2d3SChris Wilson 
766112ed2d3SChris Wilson out:
767cb823ed9SChris Wilson 	igt_global_reset_unlock(&i915->gt);
768112ed2d3SChris Wilson 	return err;
769112ed2d3SChris Wilson }
770112ed2d3SChris Wilson 
771112ed2d3SChris Wilson static int read_whitelisted_registers(struct i915_gem_context *ctx,
772112ed2d3SChris Wilson 				      struct intel_engine_cs *engine,
773112ed2d3SChris Wilson 				      struct i915_vma *results)
774112ed2d3SChris Wilson {
775112ed2d3SChris Wilson 	struct i915_request *rq;
776112ed2d3SChris Wilson 	int i, err = 0;
777112ed2d3SChris Wilson 	u32 srm, *cs;
778112ed2d3SChris Wilson 
77946472b3eSChris Wilson 	rq = igt_request_alloc(ctx, engine);
780112ed2d3SChris Wilson 	if (IS_ERR(rq))
781112ed2d3SChris Wilson 		return PTR_ERR(rq);
782112ed2d3SChris Wilson 
783112ed2d3SChris Wilson 	srm = MI_STORE_REGISTER_MEM;
784112ed2d3SChris Wilson 	if (INTEL_GEN(ctx->i915) >= 8)
785112ed2d3SChris Wilson 		srm++;
786112ed2d3SChris Wilson 
787112ed2d3SChris Wilson 	cs = intel_ring_begin(rq, 4 * engine->whitelist.count);
788112ed2d3SChris Wilson 	if (IS_ERR(cs)) {
789112ed2d3SChris Wilson 		err = PTR_ERR(cs);
790112ed2d3SChris Wilson 		goto err_req;
791112ed2d3SChris Wilson 	}
792112ed2d3SChris Wilson 
793112ed2d3SChris Wilson 	for (i = 0; i < engine->whitelist.count; i++) {
794112ed2d3SChris Wilson 		u64 offset = results->node.start + sizeof(u32) * i;
795767662bcSRobert M. Fosha 		u32 reg = i915_mmio_reg_offset(engine->whitelist.list[i].reg);
796767662bcSRobert M. Fosha 
7971e2b7f49SJohn Harrison 		/* Clear access permission field */
7981e2b7f49SJohn Harrison 		reg &= ~RING_FORCE_TO_NONPRIV_ACCESS_MASK;
799112ed2d3SChris Wilson 
800112ed2d3SChris Wilson 		*cs++ = srm;
801767662bcSRobert M. Fosha 		*cs++ = reg;
802112ed2d3SChris Wilson 		*cs++ = lower_32_bits(offset);
803112ed2d3SChris Wilson 		*cs++ = upper_32_bits(offset);
804112ed2d3SChris Wilson 	}
805112ed2d3SChris Wilson 	intel_ring_advance(rq, cs);
806112ed2d3SChris Wilson 
807112ed2d3SChris Wilson err_req:
808112ed2d3SChris Wilson 	i915_request_add(rq);
809112ed2d3SChris Wilson 
8102f530945SChris Wilson 	if (i915_request_wait(rq, 0, HZ / 5) < 0)
811112ed2d3SChris Wilson 		err = -EIO;
812112ed2d3SChris Wilson 
813112ed2d3SChris Wilson 	return err;
814112ed2d3SChris Wilson }
815112ed2d3SChris Wilson 
816112ed2d3SChris Wilson static int scrub_whitelisted_registers(struct i915_gem_context *ctx,
817112ed2d3SChris Wilson 				       struct intel_engine_cs *engine)
818112ed2d3SChris Wilson {
819112ed2d3SChris Wilson 	struct i915_request *rq;
820112ed2d3SChris Wilson 	struct i915_vma *batch;
821112ed2d3SChris Wilson 	int i, err = 0;
822112ed2d3SChris Wilson 	u32 *cs;
823112ed2d3SChris Wilson 
824112ed2d3SChris Wilson 	batch = create_batch(ctx);
825112ed2d3SChris Wilson 	if (IS_ERR(batch))
826112ed2d3SChris Wilson 		return PTR_ERR(batch);
827112ed2d3SChris Wilson 
828112ed2d3SChris Wilson 	cs = i915_gem_object_pin_map(batch->obj, I915_MAP_WC);
829112ed2d3SChris Wilson 	if (IS_ERR(cs)) {
830112ed2d3SChris Wilson 		err = PTR_ERR(cs);
831112ed2d3SChris Wilson 		goto err_batch;
832112ed2d3SChris Wilson 	}
833112ed2d3SChris Wilson 
834767662bcSRobert M. Fosha 	*cs++ = MI_LOAD_REGISTER_IMM(whitelist_writable_count(engine));
835112ed2d3SChris Wilson 	for (i = 0; i < engine->whitelist.count; i++) {
836767662bcSRobert M. Fosha 		u32 reg = i915_mmio_reg_offset(engine->whitelist.list[i].reg);
837767662bcSRobert M. Fosha 
838767662bcSRobert M. Fosha 		if (ro_register(reg))
839767662bcSRobert M. Fosha 			continue;
840767662bcSRobert M. Fosha 
841767662bcSRobert M. Fosha 		*cs++ = reg;
842112ed2d3SChris Wilson 		*cs++ = 0xffffffff;
843112ed2d3SChris Wilson 	}
844112ed2d3SChris Wilson 	*cs++ = MI_BATCH_BUFFER_END;
845112ed2d3SChris Wilson 
846112ed2d3SChris Wilson 	i915_gem_object_flush_map(batch->obj);
847baea429dSTvrtko Ursulin 	intel_gt_chipset_flush(engine->gt);
848112ed2d3SChris Wilson 
84946472b3eSChris Wilson 	rq = igt_request_alloc(ctx, engine);
850112ed2d3SChris Wilson 	if (IS_ERR(rq)) {
851112ed2d3SChris Wilson 		err = PTR_ERR(rq);
852112ed2d3SChris Wilson 		goto err_unpin;
853112ed2d3SChris Wilson 	}
854112ed2d3SChris Wilson 
855112ed2d3SChris Wilson 	if (engine->emit_init_breadcrumb) { /* Be nice if we hang */
856112ed2d3SChris Wilson 		err = engine->emit_init_breadcrumb(rq);
857112ed2d3SChris Wilson 		if (err)
858112ed2d3SChris Wilson 			goto err_request;
859112ed2d3SChris Wilson 	}
860112ed2d3SChris Wilson 
8611d5b7773SChris Wilson 	i915_vma_lock(batch);
8621d5b7773SChris Wilson 	err = i915_request_await_object(rq, batch->obj, false);
8631d5b7773SChris Wilson 	if (err == 0)
8641d5b7773SChris Wilson 		err = i915_vma_move_to_active(batch, rq, 0);
8651d5b7773SChris Wilson 	i915_vma_unlock(batch);
8661d5b7773SChris Wilson 	if (err)
8671d5b7773SChris Wilson 		goto err_request;
8681d5b7773SChris Wilson 
869112ed2d3SChris Wilson 	/* Perform the writes from an unprivileged "user" batch */
870112ed2d3SChris Wilson 	err = engine->emit_bb_start(rq, batch->node.start, 0, 0);
871112ed2d3SChris Wilson 
872112ed2d3SChris Wilson err_request:
873112ed2d3SChris Wilson 	i915_request_add(rq);
8742f530945SChris Wilson 	if (i915_request_wait(rq, 0, HZ / 5) < 0)
875112ed2d3SChris Wilson 		err = -EIO;
876112ed2d3SChris Wilson 
877112ed2d3SChris Wilson err_unpin:
878112ed2d3SChris Wilson 	i915_gem_object_unpin_map(batch->obj);
879112ed2d3SChris Wilson err_batch:
880112ed2d3SChris Wilson 	i915_vma_unpin_and_release(&batch, 0);
881112ed2d3SChris Wilson 	return err;
882112ed2d3SChris Wilson }
883112ed2d3SChris Wilson 
884112ed2d3SChris Wilson struct regmask {
885112ed2d3SChris Wilson 	i915_reg_t reg;
886112ed2d3SChris Wilson 	unsigned long gen_mask;
887112ed2d3SChris Wilson };
888112ed2d3SChris Wilson 
889112ed2d3SChris Wilson static bool find_reg(struct drm_i915_private *i915,
890112ed2d3SChris Wilson 		     i915_reg_t reg,
891112ed2d3SChris Wilson 		     const struct regmask *tbl,
892112ed2d3SChris Wilson 		     unsigned long count)
893112ed2d3SChris Wilson {
894112ed2d3SChris Wilson 	u32 offset = i915_mmio_reg_offset(reg);
895112ed2d3SChris Wilson 
896112ed2d3SChris Wilson 	while (count--) {
897112ed2d3SChris Wilson 		if (INTEL_INFO(i915)->gen_mask & tbl->gen_mask &&
898112ed2d3SChris Wilson 		    i915_mmio_reg_offset(tbl->reg) == offset)
899112ed2d3SChris Wilson 			return true;
900112ed2d3SChris Wilson 		tbl++;
901112ed2d3SChris Wilson 	}
902112ed2d3SChris Wilson 
903112ed2d3SChris Wilson 	return false;
904112ed2d3SChris Wilson }
905112ed2d3SChris Wilson 
906112ed2d3SChris Wilson static bool pardon_reg(struct drm_i915_private *i915, i915_reg_t reg)
907112ed2d3SChris Wilson {
908112ed2d3SChris Wilson 	/* Alas, we must pardon some whitelists. Mistakes already made */
909112ed2d3SChris Wilson 	static const struct regmask pardon[] = {
910112ed2d3SChris Wilson 		{ GEN9_CTX_PREEMPT_REG, INTEL_GEN_MASK(9, 9) },
911112ed2d3SChris Wilson 		{ GEN8_L3SQCREG4, INTEL_GEN_MASK(9, 9) },
912112ed2d3SChris Wilson 	};
913112ed2d3SChris Wilson 
914112ed2d3SChris Wilson 	return find_reg(i915, reg, pardon, ARRAY_SIZE(pardon));
915112ed2d3SChris Wilson }
916112ed2d3SChris Wilson 
917112ed2d3SChris Wilson static bool result_eq(struct intel_engine_cs *engine,
918112ed2d3SChris Wilson 		      u32 a, u32 b, i915_reg_t reg)
919112ed2d3SChris Wilson {
920112ed2d3SChris Wilson 	if (a != b && !pardon_reg(engine->i915, reg)) {
921112ed2d3SChris Wilson 		pr_err("Whitelisted register 0x%4x not context saved: A=%08x, B=%08x\n",
922112ed2d3SChris Wilson 		       i915_mmio_reg_offset(reg), a, b);
923112ed2d3SChris Wilson 		return false;
924112ed2d3SChris Wilson 	}
925112ed2d3SChris Wilson 
926112ed2d3SChris Wilson 	return true;
927112ed2d3SChris Wilson }
928112ed2d3SChris Wilson 
929112ed2d3SChris Wilson static bool writeonly_reg(struct drm_i915_private *i915, i915_reg_t reg)
930112ed2d3SChris Wilson {
931112ed2d3SChris Wilson 	/* Some registers do not seem to behave and our writes unreadable */
932112ed2d3SChris Wilson 	static const struct regmask wo[] = {
933112ed2d3SChris Wilson 		{ GEN9_SLICE_COMMON_ECO_CHICKEN1, INTEL_GEN_MASK(9, 9) },
934112ed2d3SChris Wilson 	};
935112ed2d3SChris Wilson 
936112ed2d3SChris Wilson 	return find_reg(i915, reg, wo, ARRAY_SIZE(wo));
937112ed2d3SChris Wilson }
938112ed2d3SChris Wilson 
939112ed2d3SChris Wilson static bool result_neq(struct intel_engine_cs *engine,
940112ed2d3SChris Wilson 		       u32 a, u32 b, i915_reg_t reg)
941112ed2d3SChris Wilson {
942112ed2d3SChris Wilson 	if (a == b && !writeonly_reg(engine->i915, reg)) {
943112ed2d3SChris Wilson 		pr_err("Whitelist register 0x%4x:%08x was unwritable\n",
944112ed2d3SChris Wilson 		       i915_mmio_reg_offset(reg), a);
945112ed2d3SChris Wilson 		return false;
946112ed2d3SChris Wilson 	}
947112ed2d3SChris Wilson 
948112ed2d3SChris Wilson 	return true;
949112ed2d3SChris Wilson }
950112ed2d3SChris Wilson 
951112ed2d3SChris Wilson static int
952112ed2d3SChris Wilson check_whitelisted_registers(struct intel_engine_cs *engine,
953112ed2d3SChris Wilson 			    struct i915_vma *A,
954112ed2d3SChris Wilson 			    struct i915_vma *B,
955112ed2d3SChris Wilson 			    bool (*fn)(struct intel_engine_cs *engine,
956112ed2d3SChris Wilson 				       u32 a, u32 b,
957112ed2d3SChris Wilson 				       i915_reg_t reg))
958112ed2d3SChris Wilson {
959112ed2d3SChris Wilson 	u32 *a, *b;
960112ed2d3SChris Wilson 	int i, err;
961112ed2d3SChris Wilson 
962112ed2d3SChris Wilson 	a = i915_gem_object_pin_map(A->obj, I915_MAP_WB);
963112ed2d3SChris Wilson 	if (IS_ERR(a))
964112ed2d3SChris Wilson 		return PTR_ERR(a);
965112ed2d3SChris Wilson 
966112ed2d3SChris Wilson 	b = i915_gem_object_pin_map(B->obj, I915_MAP_WB);
967112ed2d3SChris Wilson 	if (IS_ERR(b)) {
968112ed2d3SChris Wilson 		err = PTR_ERR(b);
969112ed2d3SChris Wilson 		goto err_a;
970112ed2d3SChris Wilson 	}
971112ed2d3SChris Wilson 
972112ed2d3SChris Wilson 	err = 0;
973112ed2d3SChris Wilson 	for (i = 0; i < engine->whitelist.count; i++) {
974361b6905SLionel Landwerlin 		const struct i915_wa *wa = &engine->whitelist.list[i];
975361b6905SLionel Landwerlin 
9761e2b7f49SJohn Harrison 		if (i915_mmio_reg_offset(wa->reg) &
9771e2b7f49SJohn Harrison 		    RING_FORCE_TO_NONPRIV_ACCESS_RD)
978361b6905SLionel Landwerlin 			continue;
979361b6905SLionel Landwerlin 
980361b6905SLionel Landwerlin 		if (!fn(engine, a[i], b[i], wa->reg))
981112ed2d3SChris Wilson 			err = -EINVAL;
982112ed2d3SChris Wilson 	}
983112ed2d3SChris Wilson 
984112ed2d3SChris Wilson 	i915_gem_object_unpin_map(B->obj);
985112ed2d3SChris Wilson err_a:
986112ed2d3SChris Wilson 	i915_gem_object_unpin_map(A->obj);
987112ed2d3SChris Wilson 	return err;
988112ed2d3SChris Wilson }
989112ed2d3SChris Wilson 
990112ed2d3SChris Wilson static int live_isolated_whitelist(void *arg)
991112ed2d3SChris Wilson {
992112ed2d3SChris Wilson 	struct drm_i915_private *i915 = arg;
993112ed2d3SChris Wilson 	struct {
994112ed2d3SChris Wilson 		struct i915_gem_context *ctx;
995112ed2d3SChris Wilson 		struct i915_vma *scratch[2];
996112ed2d3SChris Wilson 	} client[2] = {};
997112ed2d3SChris Wilson 	struct intel_engine_cs *engine;
998112ed2d3SChris Wilson 	enum intel_engine_id id;
999112ed2d3SChris Wilson 	int i, err = 0;
1000112ed2d3SChris Wilson 
1001112ed2d3SChris Wilson 	/*
1002112ed2d3SChris Wilson 	 * Check that a write into a whitelist register works, but
1003112ed2d3SChris Wilson 	 * invisible to a second context.
1004112ed2d3SChris Wilson 	 */
1005112ed2d3SChris Wilson 
1006112ed2d3SChris Wilson 	if (!intel_engines_has_context_isolation(i915))
1007112ed2d3SChris Wilson 		return 0;
1008112ed2d3SChris Wilson 
1009e568ac38SChris Wilson 	if (!i915->kernel_context->vm)
1010112ed2d3SChris Wilson 		return 0;
1011112ed2d3SChris Wilson 
1012112ed2d3SChris Wilson 	for (i = 0; i < ARRAY_SIZE(client); i++) {
1013112ed2d3SChris Wilson 		struct i915_gem_context *c;
1014112ed2d3SChris Wilson 
1015112ed2d3SChris Wilson 		c = kernel_context(i915);
1016112ed2d3SChris Wilson 		if (IS_ERR(c)) {
1017112ed2d3SChris Wilson 			err = PTR_ERR(c);
1018112ed2d3SChris Wilson 			goto err;
1019112ed2d3SChris Wilson 		}
1020112ed2d3SChris Wilson 
1021e568ac38SChris Wilson 		client[i].scratch[0] = create_scratch(c->vm, 1024);
1022112ed2d3SChris Wilson 		if (IS_ERR(client[i].scratch[0])) {
1023112ed2d3SChris Wilson 			err = PTR_ERR(client[i].scratch[0]);
1024112ed2d3SChris Wilson 			kernel_context_close(c);
1025112ed2d3SChris Wilson 			goto err;
1026112ed2d3SChris Wilson 		}
1027112ed2d3SChris Wilson 
1028e568ac38SChris Wilson 		client[i].scratch[1] = create_scratch(c->vm, 1024);
1029112ed2d3SChris Wilson 		if (IS_ERR(client[i].scratch[1])) {
1030112ed2d3SChris Wilson 			err = PTR_ERR(client[i].scratch[1]);
1031112ed2d3SChris Wilson 			i915_vma_unpin_and_release(&client[i].scratch[0], 0);
1032112ed2d3SChris Wilson 			kernel_context_close(c);
1033112ed2d3SChris Wilson 			goto err;
1034112ed2d3SChris Wilson 		}
1035112ed2d3SChris Wilson 
1036112ed2d3SChris Wilson 		client[i].ctx = c;
1037112ed2d3SChris Wilson 	}
1038112ed2d3SChris Wilson 
1039112ed2d3SChris Wilson 	for_each_engine(engine, i915, id) {
1040767662bcSRobert M. Fosha 		if (!whitelist_writable_count(engine))
1041112ed2d3SChris Wilson 			continue;
1042112ed2d3SChris Wilson 
1043112ed2d3SChris Wilson 		/* Read default values */
1044112ed2d3SChris Wilson 		err = read_whitelisted_registers(client[0].ctx, engine,
1045112ed2d3SChris Wilson 						 client[0].scratch[0]);
1046112ed2d3SChris Wilson 		if (err)
1047112ed2d3SChris Wilson 			goto err;
1048112ed2d3SChris Wilson 
1049112ed2d3SChris Wilson 		/* Try to overwrite registers (should only affect ctx0) */
1050112ed2d3SChris Wilson 		err = scrub_whitelisted_registers(client[0].ctx, engine);
1051112ed2d3SChris Wilson 		if (err)
1052112ed2d3SChris Wilson 			goto err;
1053112ed2d3SChris Wilson 
1054112ed2d3SChris Wilson 		/* Read values from ctx1, we expect these to be defaults */
1055112ed2d3SChris Wilson 		err = read_whitelisted_registers(client[1].ctx, engine,
1056112ed2d3SChris Wilson 						 client[1].scratch[0]);
1057112ed2d3SChris Wilson 		if (err)
1058112ed2d3SChris Wilson 			goto err;
1059112ed2d3SChris Wilson 
1060112ed2d3SChris Wilson 		/* Verify that both reads return the same default values */
1061112ed2d3SChris Wilson 		err = check_whitelisted_registers(engine,
1062112ed2d3SChris Wilson 						  client[0].scratch[0],
1063112ed2d3SChris Wilson 						  client[1].scratch[0],
1064112ed2d3SChris Wilson 						  result_eq);
1065112ed2d3SChris Wilson 		if (err)
1066112ed2d3SChris Wilson 			goto err;
1067112ed2d3SChris Wilson 
1068112ed2d3SChris Wilson 		/* Read back the updated values in ctx0 */
1069112ed2d3SChris Wilson 		err = read_whitelisted_registers(client[0].ctx, engine,
1070112ed2d3SChris Wilson 						 client[0].scratch[1]);
1071112ed2d3SChris Wilson 		if (err)
1072112ed2d3SChris Wilson 			goto err;
1073112ed2d3SChris Wilson 
1074112ed2d3SChris Wilson 		/* User should be granted privilege to overwhite regs */
1075112ed2d3SChris Wilson 		err = check_whitelisted_registers(engine,
1076112ed2d3SChris Wilson 						  client[0].scratch[0],
1077112ed2d3SChris Wilson 						  client[0].scratch[1],
1078112ed2d3SChris Wilson 						  result_neq);
1079112ed2d3SChris Wilson 		if (err)
1080112ed2d3SChris Wilson 			goto err;
1081112ed2d3SChris Wilson 	}
1082112ed2d3SChris Wilson 
1083112ed2d3SChris Wilson err:
1084112ed2d3SChris Wilson 	for (i = 0; i < ARRAY_SIZE(client); i++) {
1085112ed2d3SChris Wilson 		if (!client[i].ctx)
1086112ed2d3SChris Wilson 			break;
1087112ed2d3SChris Wilson 
1088112ed2d3SChris Wilson 		i915_vma_unpin_and_release(&client[i].scratch[1], 0);
1089112ed2d3SChris Wilson 		i915_vma_unpin_and_release(&client[i].scratch[0], 0);
1090112ed2d3SChris Wilson 		kernel_context_close(client[i].ctx);
1091112ed2d3SChris Wilson 	}
1092112ed2d3SChris Wilson 
1093112ed2d3SChris Wilson 	if (igt_flush_test(i915, I915_WAIT_LOCKED))
1094112ed2d3SChris Wilson 		err = -EIO;
1095112ed2d3SChris Wilson 
1096112ed2d3SChris Wilson 	return err;
1097112ed2d3SChris Wilson }
1098112ed2d3SChris Wilson 
1099fde93886STvrtko Ursulin static bool
1100fde93886STvrtko Ursulin verify_wa_lists(struct i915_gem_context *ctx, struct wa_lists *lists,
1101fde93886STvrtko Ursulin 		const char *str)
1102112ed2d3SChris Wilson {
1103fde93886STvrtko Ursulin 	struct drm_i915_private *i915 = ctx->i915;
1104fde93886STvrtko Ursulin 	struct i915_gem_engines_iter it;
1105fde93886STvrtko Ursulin 	struct intel_context *ce;
1106112ed2d3SChris Wilson 	bool ok = true;
1107112ed2d3SChris Wilson 
1108112ed2d3SChris Wilson 	ok &= wa_list_verify(&i915->uncore, &lists->gt_wa_list, str);
1109112ed2d3SChris Wilson 
1110f277bc0cSChris Wilson 	for_each_gem_engine(ce, i915_gem_context_engines(ctx), it) {
1111fde93886STvrtko Ursulin 		enum intel_engine_id id = ce->engine->id;
1112fde93886STvrtko Ursulin 
1113fde93886STvrtko Ursulin 		ok &= engine_wa_list_verify(ce,
1114112ed2d3SChris Wilson 					    &lists->engine[id].wa_list,
1115112ed2d3SChris Wilson 					    str) == 0;
1116fde93886STvrtko Ursulin 
1117fde93886STvrtko Ursulin 		ok &= engine_wa_list_verify(ce,
1118fde93886STvrtko Ursulin 					    &lists->engine[id].ctx_wa_list,
1119fde93886STvrtko Ursulin 					    str) == 0;
1120112ed2d3SChris Wilson 	}
1121112ed2d3SChris Wilson 
1122112ed2d3SChris Wilson 	return ok;
1123112ed2d3SChris Wilson }
1124112ed2d3SChris Wilson 
1125112ed2d3SChris Wilson static int
1126fde93886STvrtko Ursulin live_gpu_reset_workarounds(void *arg)
1127112ed2d3SChris Wilson {
1128112ed2d3SChris Wilson 	struct drm_i915_private *i915 = arg;
1129fde93886STvrtko Ursulin 	struct i915_gem_context *ctx;
1130112ed2d3SChris Wilson 	intel_wakeref_t wakeref;
1131112ed2d3SChris Wilson 	struct wa_lists lists;
1132112ed2d3SChris Wilson 	bool ok;
1133112ed2d3SChris Wilson 
1134112ed2d3SChris Wilson 	if (!intel_has_gpu_reset(i915))
1135112ed2d3SChris Wilson 		return 0;
1136112ed2d3SChris Wilson 
1137fde93886STvrtko Ursulin 	ctx = kernel_context(i915);
1138fde93886STvrtko Ursulin 	if (IS_ERR(ctx))
1139fde93886STvrtko Ursulin 		return PTR_ERR(ctx);
1140fde93886STvrtko Ursulin 
1141f277bc0cSChris Wilson 	i915_gem_context_lock_engines(ctx);
1142f277bc0cSChris Wilson 
1143112ed2d3SChris Wilson 	pr_info("Verifying after GPU reset...\n");
1144112ed2d3SChris Wilson 
1145cb823ed9SChris Wilson 	igt_global_reset_lock(&i915->gt);
1146d858d569SDaniele Ceraolo Spurio 	wakeref = intel_runtime_pm_get(&i915->runtime_pm);
1147112ed2d3SChris Wilson 
1148112ed2d3SChris Wilson 	reference_lists_init(i915, &lists);
1149112ed2d3SChris Wilson 
1150fde93886STvrtko Ursulin 	ok = verify_wa_lists(ctx, &lists, "before reset");
1151112ed2d3SChris Wilson 	if (!ok)
1152112ed2d3SChris Wilson 		goto out;
1153112ed2d3SChris Wilson 
1154cb823ed9SChris Wilson 	intel_gt_reset(&i915->gt, ALL_ENGINES, "live_workarounds");
1155112ed2d3SChris Wilson 
1156fde93886STvrtko Ursulin 	ok = verify_wa_lists(ctx, &lists, "after reset");
1157112ed2d3SChris Wilson 
1158112ed2d3SChris Wilson out:
1159f277bc0cSChris Wilson 	i915_gem_context_unlock_engines(ctx);
1160fde93886STvrtko Ursulin 	kernel_context_close(ctx);
1161112ed2d3SChris Wilson 	reference_lists_fini(i915, &lists);
1162d858d569SDaniele Ceraolo Spurio 	intel_runtime_pm_put(&i915->runtime_pm, wakeref);
1163cb823ed9SChris Wilson 	igt_global_reset_unlock(&i915->gt);
1164112ed2d3SChris Wilson 
1165112ed2d3SChris Wilson 	return ok ? 0 : -ESRCH;
1166112ed2d3SChris Wilson }
1167112ed2d3SChris Wilson 
1168112ed2d3SChris Wilson static int
1169fde93886STvrtko Ursulin live_engine_reset_workarounds(void *arg)
1170112ed2d3SChris Wilson {
1171112ed2d3SChris Wilson 	struct drm_i915_private *i915 = arg;
1172f277bc0cSChris Wilson 	struct i915_gem_engines_iter it;
1173112ed2d3SChris Wilson 	struct i915_gem_context *ctx;
1174f277bc0cSChris Wilson 	struct intel_context *ce;
1175112ed2d3SChris Wilson 	struct igt_spinner spin;
1176112ed2d3SChris Wilson 	struct i915_request *rq;
1177112ed2d3SChris Wilson 	intel_wakeref_t wakeref;
1178112ed2d3SChris Wilson 	struct wa_lists lists;
1179112ed2d3SChris Wilson 	int ret = 0;
1180112ed2d3SChris Wilson 
1181112ed2d3SChris Wilson 	if (!intel_has_reset_engine(i915))
1182112ed2d3SChris Wilson 		return 0;
1183112ed2d3SChris Wilson 
1184112ed2d3SChris Wilson 	ctx = kernel_context(i915);
1185112ed2d3SChris Wilson 	if (IS_ERR(ctx))
1186112ed2d3SChris Wilson 		return PTR_ERR(ctx);
1187112ed2d3SChris Wilson 
1188cb823ed9SChris Wilson 	igt_global_reset_lock(&i915->gt);
1189d858d569SDaniele Ceraolo Spurio 	wakeref = intel_runtime_pm_get(&i915->runtime_pm);
1190112ed2d3SChris Wilson 
1191112ed2d3SChris Wilson 	reference_lists_init(i915, &lists);
1192112ed2d3SChris Wilson 
1193f277bc0cSChris Wilson 	for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) {
1194f277bc0cSChris Wilson 		struct intel_engine_cs *engine = ce->engine;
1195112ed2d3SChris Wilson 		bool ok;
1196112ed2d3SChris Wilson 
1197112ed2d3SChris Wilson 		pr_info("Verifying after %s reset...\n", engine->name);
1198112ed2d3SChris Wilson 
1199fde93886STvrtko Ursulin 		ok = verify_wa_lists(ctx, &lists, "before reset");
1200112ed2d3SChris Wilson 		if (!ok) {
1201112ed2d3SChris Wilson 			ret = -ESRCH;
1202112ed2d3SChris Wilson 			goto err;
1203112ed2d3SChris Wilson 		}
1204112ed2d3SChris Wilson 
1205cb823ed9SChris Wilson 		intel_engine_reset(engine, "live_workarounds");
1206112ed2d3SChris Wilson 
1207fde93886STvrtko Ursulin 		ok = verify_wa_lists(ctx, &lists, "after idle reset");
1208112ed2d3SChris Wilson 		if (!ok) {
1209112ed2d3SChris Wilson 			ret = -ESRCH;
1210112ed2d3SChris Wilson 			goto err;
1211112ed2d3SChris Wilson 		}
1212112ed2d3SChris Wilson 
1213f277bc0cSChris Wilson 		ret = igt_spinner_init(&spin, engine->gt);
1214112ed2d3SChris Wilson 		if (ret)
1215112ed2d3SChris Wilson 			goto err;
1216112ed2d3SChris Wilson 
1217f277bc0cSChris Wilson 		rq = igt_spinner_create_request(&spin, ce, MI_NOOP);
1218112ed2d3SChris Wilson 		if (IS_ERR(rq)) {
1219112ed2d3SChris Wilson 			ret = PTR_ERR(rq);
1220112ed2d3SChris Wilson 			igt_spinner_fini(&spin);
1221112ed2d3SChris Wilson 			goto err;
1222112ed2d3SChris Wilson 		}
1223112ed2d3SChris Wilson 
1224112ed2d3SChris Wilson 		i915_request_add(rq);
1225112ed2d3SChris Wilson 
1226112ed2d3SChris Wilson 		if (!igt_wait_for_spinner(&spin, rq)) {
1227112ed2d3SChris Wilson 			pr_err("Spinner failed to start\n");
1228112ed2d3SChris Wilson 			igt_spinner_fini(&spin);
1229112ed2d3SChris Wilson 			ret = -ETIMEDOUT;
1230112ed2d3SChris Wilson 			goto err;
1231112ed2d3SChris Wilson 		}
1232112ed2d3SChris Wilson 
1233cb823ed9SChris Wilson 		intel_engine_reset(engine, "live_workarounds");
1234112ed2d3SChris Wilson 
1235112ed2d3SChris Wilson 		igt_spinner_end(&spin);
1236112ed2d3SChris Wilson 		igt_spinner_fini(&spin);
1237112ed2d3SChris Wilson 
1238fde93886STvrtko Ursulin 		ok = verify_wa_lists(ctx, &lists, "after busy reset");
1239112ed2d3SChris Wilson 		if (!ok) {
1240112ed2d3SChris Wilson 			ret = -ESRCH;
1241112ed2d3SChris Wilson 			goto err;
1242112ed2d3SChris Wilson 		}
1243112ed2d3SChris Wilson 	}
1244112ed2d3SChris Wilson err:
1245f277bc0cSChris Wilson 	i915_gem_context_unlock_engines(ctx);
1246112ed2d3SChris Wilson 	reference_lists_fini(i915, &lists);
1247d858d569SDaniele Ceraolo Spurio 	intel_runtime_pm_put(&i915->runtime_pm, wakeref);
1248cb823ed9SChris Wilson 	igt_global_reset_unlock(&i915->gt);
1249112ed2d3SChris Wilson 	kernel_context_close(ctx);
1250112ed2d3SChris Wilson 
1251112ed2d3SChris Wilson 	igt_flush_test(i915, I915_WAIT_LOCKED);
1252112ed2d3SChris Wilson 
1253112ed2d3SChris Wilson 	return ret;
1254112ed2d3SChris Wilson }
1255112ed2d3SChris Wilson 
1256112ed2d3SChris Wilson int intel_workarounds_live_selftests(struct drm_i915_private *i915)
1257112ed2d3SChris Wilson {
1258112ed2d3SChris Wilson 	static const struct i915_subtest tests[] = {
1259112ed2d3SChris Wilson 		SUBTEST(live_dirty_whitelist),
1260112ed2d3SChris Wilson 		SUBTEST(live_reset_whitelist),
1261112ed2d3SChris Wilson 		SUBTEST(live_isolated_whitelist),
1262fde93886STvrtko Ursulin 		SUBTEST(live_gpu_reset_workarounds),
1263fde93886STvrtko Ursulin 		SUBTEST(live_engine_reset_workarounds),
1264112ed2d3SChris Wilson 	};
1265112ed2d3SChris Wilson 	int err;
1266112ed2d3SChris Wilson 
1267cb823ed9SChris Wilson 	if (intel_gt_is_wedged(&i915->gt))
1268112ed2d3SChris Wilson 		return 0;
1269112ed2d3SChris Wilson 
1270112ed2d3SChris Wilson 	mutex_lock(&i915->drm.struct_mutex);
1271112ed2d3SChris Wilson 	err = i915_subtests(tests, i915);
1272112ed2d3SChris Wilson 	mutex_unlock(&i915->drm.struct_mutex);
1273112ed2d3SChris Wilson 
1274112ed2d3SChris Wilson 	return err;
1275112ed2d3SChris Wilson }
1276