Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: MIT
  2/*
  3 * Copyright © 2018 Intel Corporation
  4 */
  5
  6#include <linux/crc32.h>
  7
  8#include "gem/i915_gem_stolen.h"
  9
 10#include "i915_memcpy.h"
 11#include "i915_selftest.h"
 12#include "intel_gpu_commands.h"
 13#include "selftests/igt_reset.h"
 14#include "selftests/igt_atomic.h"
 15#include "selftests/igt_spinner.h"
 16
 17static int
 18__igt_reset_stolen(struct intel_gt *gt,
 19		   intel_engine_mask_t mask,
 20		   const char *msg)
 21{
 22	struct i915_ggtt *ggtt = gt->ggtt;
 23	const struct resource *dsm = &gt->i915->dsm.stolen;
 24	resource_size_t num_pages, page;
 25	struct intel_engine_cs *engine;
 26	intel_wakeref_t wakeref;
 27	enum intel_engine_id id;
 28	struct igt_spinner spin;
 29	long max, count;
 30	void *tmp;
 31	u32 *crc;
 32	int err;
 33
 34	if (!drm_mm_node_allocated(&ggtt->error_capture))
 35		return 0;
 36
 37	num_pages = resource_size(dsm) >> PAGE_SHIFT;
 38	if (!num_pages)
 39		return 0;
 40
 41	crc = kmalloc_array(num_pages, sizeof(u32), GFP_KERNEL);
 42	if (!crc)
 43		return -ENOMEM;
 44
 45	tmp = kmalloc(PAGE_SIZE, GFP_KERNEL);
 46	if (!tmp) {
 47		err = -ENOMEM;
 48		goto err_crc;
 49	}
 50
 51	igt_global_reset_lock(gt);
 52	wakeref = intel_runtime_pm_get(gt->uncore->rpm);
 53
 54	err = igt_spinner_init(&spin, gt);
 55	if (err)
 56		goto err_lock;
 57
 58	for_each_engine(engine, gt, id) {
 59		struct intel_context *ce;
 60		struct i915_request *rq;
 61
 62		if (!(mask & engine->mask))
 63			continue;
 64
 65		if (!intel_engine_can_store_dword(engine))
 66			continue;
 67
 68		ce = intel_context_create(engine);
 69		if (IS_ERR(ce)) {
 70			err = PTR_ERR(ce);
 71			goto err_spin;
 72		}
 73		rq = igt_spinner_create_request(&spin, ce, MI_ARB_CHECK);
 74		intel_context_put(ce);
 75		if (IS_ERR(rq)) {
 76			err = PTR_ERR(rq);
 77			goto err_spin;
 78		}
 79		i915_request_add(rq);
 80	}
 81
 82	for (page = 0; page < num_pages; page++) {
 83		dma_addr_t dma = (dma_addr_t)dsm->start + (page << PAGE_SHIFT);
 84		void __iomem *s;
 85		void *in;
 86
 87		ggtt->vm.insert_page(&ggtt->vm, dma,
 88				     ggtt->error_capture.start,
 89				     i915_gem_get_pat_index(gt->i915,
 90							    I915_CACHE_NONE),
 91				     0);
 92		mb();
 93
 94		s = io_mapping_map_wc(&ggtt->iomap,
 95				      ggtt->error_capture.start,
 96				      PAGE_SIZE);
 97
 98		if (!__drm_mm_interval_first(&gt->i915->mm.stolen,
 99					     page << PAGE_SHIFT,
100					     ((page + 1) << PAGE_SHIFT) - 1))
101			memset_io(s, STACK_MAGIC, PAGE_SIZE);
102
103		in = (void __force *)s;
104		if (i915_memcpy_from_wc(tmp, in, PAGE_SIZE))
105			in = tmp;
106		crc[page] = crc32_le(0, in, PAGE_SIZE);
107
108		io_mapping_unmap(s);
109	}
110	mb();
111	ggtt->vm.clear_range(&ggtt->vm, ggtt->error_capture.start, PAGE_SIZE);
112
113	if (mask == ALL_ENGINES) {
114		intel_gt_reset(gt, mask, NULL);
115	} else {
116		for_each_engine(engine, gt, id) {
117			if (mask & engine->mask)
118				intel_engine_reset(engine, NULL);
119		}
120	}
121
122	max = -1;
123	count = 0;
124	for (page = 0; page < num_pages; page++) {
125		dma_addr_t dma = (dma_addr_t)dsm->start + (page << PAGE_SHIFT);
126		void __iomem *s;
127		void *in;
128		u32 x;
129
130		ggtt->vm.insert_page(&ggtt->vm, dma,
131				     ggtt->error_capture.start,
132				     i915_gem_get_pat_index(gt->i915,
133							    I915_CACHE_NONE),
134				     0);
135		mb();
136
137		s = io_mapping_map_wc(&ggtt->iomap,
138				      ggtt->error_capture.start,
139				      PAGE_SIZE);
140
141		in = (void __force *)s;
142		if (i915_memcpy_from_wc(tmp, in, PAGE_SIZE))
143			in = tmp;
144		x = crc32_le(0, in, PAGE_SIZE);
145
146		if (x != crc[page] &&
147		    !__drm_mm_interval_first(&gt->i915->mm.stolen,
148					     page << PAGE_SHIFT,
149					     ((page + 1) << PAGE_SHIFT) - 1)) {
150			pr_debug("unused stolen page %pa modified by GPU reset\n",
151				 &page);
152			if (count++ == 0)
153				igt_hexdump(in, PAGE_SIZE);
154			max = page;
155		}
156
157		io_mapping_unmap(s);
158	}
159	mb();
160	ggtt->vm.clear_range(&ggtt->vm, ggtt->error_capture.start, PAGE_SIZE);
161
162	if (count > 0) {
163		pr_info("%s reset clobbered %ld pages of stolen, last clobber at page %ld\n",
164			msg, count, max);
165	}
166	if (max >= I915_GEM_STOLEN_BIAS >> PAGE_SHIFT) {
167		pr_err("%s reset clobbered unreserved area [above %x] of stolen; may cause severe faults\n",
168		       msg, I915_GEM_STOLEN_BIAS);
169		err = -EINVAL;
170	}
171
172err_spin:
173	igt_spinner_fini(&spin);
174
175err_lock:
176	intel_runtime_pm_put(gt->uncore->rpm, wakeref);
177	igt_global_reset_unlock(gt);
178
179	kfree(tmp);
180err_crc:
181	kfree(crc);
182	return err;
183}
184
185static int igt_reset_device_stolen(void *arg)
186{
187	return __igt_reset_stolen(arg, ALL_ENGINES, "device");
188}
189
190static int igt_reset_engines_stolen(void *arg)
191{
192	struct intel_gt *gt = arg;
193	struct intel_engine_cs *engine;
194	enum intel_engine_id id;
195	int err;
196
197	if (!intel_has_reset_engine(gt))
198		return 0;
199
200	for_each_engine(engine, gt, id) {
201		err = __igt_reset_stolen(gt, engine->mask, engine->name);
202		if (err)
203			return err;
204	}
205
206	return 0;
207}
208
209static int igt_global_reset(void *arg)
210{
211	struct intel_gt *gt = arg;
212	unsigned int reset_count;
213	intel_wakeref_t wakeref;
214	int err = 0;
215
216	/* Check that we can issue a global GPU reset */
217
218	igt_global_reset_lock(gt);
219	wakeref = intel_runtime_pm_get(gt->uncore->rpm);
220
221	reset_count = i915_reset_count(&gt->i915->gpu_error);
222
223	intel_gt_reset(gt, ALL_ENGINES, NULL);
224
225	if (i915_reset_count(&gt->i915->gpu_error) == reset_count) {
226		pr_err("No GPU reset recorded!\n");
227		err = -EINVAL;
228	}
229
230	intel_runtime_pm_put(gt->uncore->rpm, wakeref);
231	igt_global_reset_unlock(gt);
232
233	if (intel_gt_is_wedged(gt))
234		err = -EIO;
235
236	return err;
237}
238
239static int igt_wedged_reset(void *arg)
240{
241	struct intel_gt *gt = arg;
242	intel_wakeref_t wakeref;
243
244	/* Check that we can recover a wedged device with a GPU reset */
245
246	igt_global_reset_lock(gt);
247	wakeref = intel_runtime_pm_get(gt->uncore->rpm);
248
249	intel_gt_set_wedged(gt);
250
251	GEM_BUG_ON(!intel_gt_is_wedged(gt));
252	intel_gt_reset(gt, ALL_ENGINES, NULL);
253
254	intel_runtime_pm_put(gt->uncore->rpm, wakeref);
255	igt_global_reset_unlock(gt);
256
257	return intel_gt_is_wedged(gt) ? -EIO : 0;
258}
259
260static int igt_atomic_reset(void *arg)
261{
262	struct intel_gt *gt = arg;
263	const typeof(*igt_atomic_phases) *p;
264	intel_wakeref_t wakeref;
265	int err = 0;
266
267	/* Check that the resets are usable from atomic context */
268
269	wakeref = intel_gt_pm_get(gt);
270	igt_global_reset_lock(gt);
271
272	/* Flush any requests before we get started and check basics */
273	if (!igt_force_reset(gt))
274		goto unlock;
275
276	for (p = igt_atomic_phases; p->name; p++) {
277		intel_engine_mask_t awake;
278
279		GEM_TRACE("__intel_gt_reset under %s\n", p->name);
280
281		awake = reset_prepare(gt);
282		p->critical_section_begin();
283
284		err = intel_gt_reset_all_engines(gt);
285
286		p->critical_section_end();
287		reset_finish(gt, awake);
288
289		if (err) {
290			pr_err("__intel_gt_reset failed under %s\n", p->name);
291			break;
292		}
293	}
294
295	/* As we poke around the guts, do a full reset before continuing. */
296	igt_force_reset(gt);
297
298unlock:
299	igt_global_reset_unlock(gt);
300	intel_gt_pm_put(gt, wakeref);
301
302	return err;
303}
304
305static int igt_atomic_engine_reset(void *arg)
306{
307	struct intel_gt *gt = arg;
308	const typeof(*igt_atomic_phases) *p;
309	struct intel_engine_cs *engine;
310	enum intel_engine_id id;
311	intel_wakeref_t wakeref;
312	int err = 0;
313
314	/* Check that the resets are usable from atomic context */
315
316	if (!intel_has_reset_engine(gt))
317		return 0;
318
319	if (intel_uc_uses_guc_submission(&gt->uc))
320		return 0;
321
322	wakeref = intel_gt_pm_get(gt);
323	igt_global_reset_lock(gt);
324
325	/* Flush any requests before we get started and check basics */
326	if (!igt_force_reset(gt))
327		goto out_unlock;
328
329	for_each_engine(engine, gt, id) {
330		struct tasklet_struct *t = &engine->sched_engine->tasklet;
331
332		if (t->func)
333			tasklet_disable(t);
334		intel_engine_pm_get(engine);
335
336		for (p = igt_atomic_phases; p->name; p++) {
337			GEM_TRACE("intel_engine_reset(%s) under %s\n",
338				  engine->name, p->name);
339			if (strcmp(p->name, "softirq"))
340				local_bh_disable();
341
342			p->critical_section_begin();
343			err = __intel_engine_reset_bh(engine, NULL);
344			p->critical_section_end();
345
346			if (strcmp(p->name, "softirq"))
347				local_bh_enable();
348
349			if (err) {
350				pr_err("intel_engine_reset(%s) failed under %s\n",
351				       engine->name, p->name);
352				break;
353			}
354		}
355
356		intel_engine_pm_put(engine);
357		if (t->func) {
358			tasklet_enable(t);
359			tasklet_hi_schedule(t);
360		}
361		if (err)
362			break;
363	}
364
365	/* As we poke around the guts, do a full reset before continuing. */
366	igt_force_reset(gt);
367
368out_unlock:
369	igt_global_reset_unlock(gt);
370	intel_gt_pm_put(gt, wakeref);
371
372	return err;
373}
374
375int intel_reset_live_selftests(struct drm_i915_private *i915)
376{
377	static const struct i915_subtest tests[] = {
378		SUBTEST(igt_global_reset), /* attempt to recover GPU first */
379		SUBTEST(igt_reset_device_stolen),
380		SUBTEST(igt_reset_engines_stolen),
381		SUBTEST(igt_wedged_reset),
382		SUBTEST(igt_atomic_reset),
383		SUBTEST(igt_atomic_engine_reset),
384	};
385	struct intel_gt *gt = to_gt(i915);
386
387	if (!intel_has_gpu_reset(gt))
388		return 0;
389
390	if (intel_gt_is_wedged(gt))
391		return -EIO; /* we're long past hope of a successful reset */
392
393	return intel_gt_live_subtests(tests, gt);
394}
v5.4
  1// SPDX-License-Identifier: MIT
  2/*
  3 * Copyright © 2018 Intel Corporation
  4 */
  5
 
 
 
 
 
  6#include "i915_selftest.h"
 
  7#include "selftests/igt_reset.h"
  8#include "selftests/igt_atomic.h"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  9
 10static int igt_global_reset(void *arg)
 11{
 12	struct intel_gt *gt = arg;
 13	unsigned int reset_count;
 14	intel_wakeref_t wakeref;
 15	int err = 0;
 16
 17	/* Check that we can issue a global GPU reset */
 18
 19	igt_global_reset_lock(gt);
 20	wakeref = intel_runtime_pm_get(&gt->i915->runtime_pm);
 21
 22	reset_count = i915_reset_count(&gt->i915->gpu_error);
 23
 24	intel_gt_reset(gt, ALL_ENGINES, NULL);
 25
 26	if (i915_reset_count(&gt->i915->gpu_error) == reset_count) {
 27		pr_err("No GPU reset recorded!\n");
 28		err = -EINVAL;
 29	}
 30
 31	intel_runtime_pm_put(&gt->i915->runtime_pm, wakeref);
 32	igt_global_reset_unlock(gt);
 33
 34	if (intel_gt_is_wedged(gt))
 35		err = -EIO;
 36
 37	return err;
 38}
 39
 40static int igt_wedged_reset(void *arg)
 41{
 42	struct intel_gt *gt = arg;
 43	intel_wakeref_t wakeref;
 44
 45	/* Check that we can recover a wedged device with a GPU reset */
 46
 47	igt_global_reset_lock(gt);
 48	wakeref = intel_runtime_pm_get(&gt->i915->runtime_pm);
 49
 50	intel_gt_set_wedged(gt);
 51
 52	GEM_BUG_ON(!intel_gt_is_wedged(gt));
 53	intel_gt_reset(gt, ALL_ENGINES, NULL);
 54
 55	intel_runtime_pm_put(&gt->i915->runtime_pm, wakeref);
 56	igt_global_reset_unlock(gt);
 57
 58	return intel_gt_is_wedged(gt) ? -EIO : 0;
 59}
 60
 61static int igt_atomic_reset(void *arg)
 62{
 63	struct intel_gt *gt = arg;
 64	const typeof(*igt_atomic_phases) *p;
 
 65	int err = 0;
 66
 67	/* Check that the resets are usable from atomic context */
 68
 69	intel_gt_pm_get(gt);
 70	igt_global_reset_lock(gt);
 71
 72	/* Flush any requests before we get started and check basics */
 73	if (!igt_force_reset(gt))
 74		goto unlock;
 75
 76	for (p = igt_atomic_phases; p->name; p++) {
 77		intel_engine_mask_t awake;
 78
 79		GEM_TRACE("__intel_gt_reset under %s\n", p->name);
 80
 81		awake = reset_prepare(gt);
 82		p->critical_section_begin();
 83
 84		err = __intel_gt_reset(gt, ALL_ENGINES);
 85
 86		p->critical_section_end();
 87		reset_finish(gt, awake);
 88
 89		if (err) {
 90			pr_err("__intel_gt_reset failed under %s\n", p->name);
 91			break;
 92		}
 93	}
 94
 95	/* As we poke around the guts, do a full reset before continuing. */
 96	igt_force_reset(gt);
 97
 98unlock:
 99	igt_global_reset_unlock(gt);
100	intel_gt_pm_put(gt);
101
102	return err;
103}
104
105static int igt_atomic_engine_reset(void *arg)
106{
107	struct intel_gt *gt = arg;
108	const typeof(*igt_atomic_phases) *p;
109	struct intel_engine_cs *engine;
110	enum intel_engine_id id;
 
111	int err = 0;
112
113	/* Check that the resets are usable from atomic context */
114
115	if (!intel_has_reset_engine(gt->i915))
116		return 0;
117
118	if (USES_GUC_SUBMISSION(gt->i915))
119		return 0;
120
121	intel_gt_pm_get(gt);
122	igt_global_reset_lock(gt);
123
124	/* Flush any requests before we get started and check basics */
125	if (!igt_force_reset(gt))
126		goto out_unlock;
127
128	for_each_engine(engine, gt->i915, id) {
129		tasklet_disable_nosync(&engine->execlists.tasklet);
 
 
 
130		intel_engine_pm_get(engine);
131
132		for (p = igt_atomic_phases; p->name; p++) {
133			GEM_TRACE("intel_engine_reset(%s) under %s\n",
134				  engine->name, p->name);
 
 
135
136			p->critical_section_begin();
137			err = intel_engine_reset(engine, NULL);
138			p->critical_section_end();
139
 
 
 
140			if (err) {
141				pr_err("intel_engine_reset(%s) failed under %s\n",
142				       engine->name, p->name);
143				break;
144			}
145		}
146
147		intel_engine_pm_put(engine);
148		tasklet_enable(&engine->execlists.tasklet);
 
 
 
149		if (err)
150			break;
151	}
152
153	/* As we poke around the guts, do a full reset before continuing. */
154	igt_force_reset(gt);
155
156out_unlock:
157	igt_global_reset_unlock(gt);
158	intel_gt_pm_put(gt);
159
160	return err;
161}
162
163int intel_reset_live_selftests(struct drm_i915_private *i915)
164{
165	static const struct i915_subtest tests[] = {
166		SUBTEST(igt_global_reset), /* attempt to recover GPU first */
 
 
167		SUBTEST(igt_wedged_reset),
168		SUBTEST(igt_atomic_reset),
169		SUBTEST(igt_atomic_engine_reset),
170	};
171	struct intel_gt *gt = &i915->gt;
172
173	if (!intel_has_gpu_reset(gt->i915))
174		return 0;
175
176	if (intel_gt_is_wedged(gt))
177		return -EIO; /* we're long past hope of a successful reset */
178
179	return intel_gt_live_subtests(tests, gt);
180}