1 // SPDX-License-Identifier: MIT
3 * Copyright © 2018 Intel Corporation
6 #include <linux/crc32.h>
8 #include "gem/i915_gem_stolen.h"
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"
18 __igt_reset_stolen(struct intel_gt *gt,
19 intel_engine_mask_t mask,
22 struct i915_ggtt *ggtt = >->i915->ggtt;
23 const struct resource *dsm = >->i915->dsm;
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;
34 if (!drm_mm_node_allocated(&ggtt->error_capture))
37 num_pages = resource_size(dsm) >> PAGE_SHIFT;
41 crc = kmalloc_array(num_pages, sizeof(u32), GFP_KERNEL);
45 tmp = kmalloc(PAGE_SIZE, GFP_KERNEL);
51 igt_global_reset_lock(gt);
52 wakeref = intel_runtime_pm_get(gt->uncore->rpm);
54 err = igt_spinner_init(&spin, gt);
58 for_each_engine(engine, gt, id) {
59 struct intel_context *ce;
60 struct i915_request *rq;
62 if (!(mask & engine->mask))
65 if (!intel_engine_can_store_dword(engine))
68 ce = intel_context_create(engine);
73 rq = igt_spinner_create_request(&spin, ce, MI_ARB_CHECK);
74 intel_context_put(ce);
82 for (page = 0; page < num_pages; page++) {
83 dma_addr_t dma = (dma_addr_t)dsm->start + (page << PAGE_SHIFT);
87 ggtt->vm.insert_page(&ggtt->vm, dma,
88 ggtt->error_capture.start,
92 s = io_mapping_map_wc(&ggtt->iomap,
93 ggtt->error_capture.start,
96 if (!__drm_mm_interval_first(>->i915->mm.stolen,
98 ((page + 1) << PAGE_SHIFT) - 1))
99 memset_io(s, STACK_MAGIC, PAGE_SIZE);
101 in = (void __force *)s;
102 if (i915_memcpy_from_wc(tmp, in, PAGE_SIZE))
104 crc[page] = crc32_le(0, in, PAGE_SIZE);
109 ggtt->vm.clear_range(&ggtt->vm, ggtt->error_capture.start, PAGE_SIZE);
111 if (mask == ALL_ENGINES) {
112 intel_gt_reset(gt, mask, NULL);
114 for_each_engine(engine, gt, id) {
115 if (mask & engine->mask)
116 intel_engine_reset(engine, NULL);
122 for (page = 0; page < num_pages; page++) {
123 dma_addr_t dma = (dma_addr_t)dsm->start + (page << PAGE_SHIFT);
128 ggtt->vm.insert_page(&ggtt->vm, dma,
129 ggtt->error_capture.start,
133 s = io_mapping_map_wc(&ggtt->iomap,
134 ggtt->error_capture.start,
137 in = (void __force *)s;
138 if (i915_memcpy_from_wc(tmp, in, PAGE_SIZE))
140 x = crc32_le(0, in, PAGE_SIZE);
142 if (x != crc[page] &&
143 !__drm_mm_interval_first(>->i915->mm.stolen,
145 ((page + 1) << PAGE_SHIFT) - 1)) {
146 pr_debug("unused stolen page %pa modified by GPU reset\n",
149 igt_hexdump(in, PAGE_SIZE);
156 ggtt->vm.clear_range(&ggtt->vm, ggtt->error_capture.start, PAGE_SIZE);
159 pr_info("%s reset clobbered %ld pages of stolen, last clobber at page %ld\n",
162 if (max >= I915_GEM_STOLEN_BIAS >> PAGE_SHIFT) {
163 pr_err("%s reset clobbered unreserved area [above %x] of stolen; may cause severe faults\n",
164 msg, I915_GEM_STOLEN_BIAS);
169 igt_spinner_fini(&spin);
172 intel_runtime_pm_put(gt->uncore->rpm, wakeref);
173 igt_global_reset_unlock(gt);
181 static int igt_reset_device_stolen(void *arg)
183 return __igt_reset_stolen(arg, ALL_ENGINES, "device");
186 static int igt_reset_engines_stolen(void *arg)
188 struct intel_gt *gt = arg;
189 struct intel_engine_cs *engine;
190 enum intel_engine_id id;
193 if (!intel_has_reset_engine(gt))
196 for_each_engine(engine, gt, id) {
197 err = __igt_reset_stolen(gt, engine->mask, engine->name);
205 static int igt_global_reset(void *arg)
207 struct intel_gt *gt = arg;
208 unsigned int reset_count;
209 intel_wakeref_t wakeref;
212 /* Check that we can issue a global GPU reset */
214 igt_global_reset_lock(gt);
215 wakeref = intel_runtime_pm_get(gt->uncore->rpm);
217 reset_count = i915_reset_count(>->i915->gpu_error);
219 intel_gt_reset(gt, ALL_ENGINES, NULL);
221 if (i915_reset_count(>->i915->gpu_error) == reset_count) {
222 pr_err("No GPU reset recorded!\n");
226 intel_runtime_pm_put(gt->uncore->rpm, wakeref);
227 igt_global_reset_unlock(gt);
229 if (intel_gt_is_wedged(gt))
235 static int igt_wedged_reset(void *arg)
237 struct intel_gt *gt = arg;
238 intel_wakeref_t wakeref;
240 /* Check that we can recover a wedged device with a GPU reset */
242 igt_global_reset_lock(gt);
243 wakeref = intel_runtime_pm_get(gt->uncore->rpm);
245 intel_gt_set_wedged(gt);
247 GEM_BUG_ON(!intel_gt_is_wedged(gt));
248 intel_gt_reset(gt, ALL_ENGINES, NULL);
250 intel_runtime_pm_put(gt->uncore->rpm, wakeref);
251 igt_global_reset_unlock(gt);
253 return intel_gt_is_wedged(gt) ? -EIO : 0;
256 static int igt_atomic_reset(void *arg)
258 struct intel_gt *gt = arg;
259 const typeof(*igt_atomic_phases) *p;
262 /* Check that the resets are usable from atomic context */
265 igt_global_reset_lock(gt);
267 /* Flush any requests before we get started and check basics */
268 if (!igt_force_reset(gt))
271 for (p = igt_atomic_phases; p->name; p++) {
272 intel_engine_mask_t awake;
274 GEM_TRACE("__intel_gt_reset under %s\n", p->name);
276 awake = reset_prepare(gt);
277 p->critical_section_begin();
279 err = __intel_gt_reset(gt, ALL_ENGINES);
281 p->critical_section_end();
282 reset_finish(gt, awake);
285 pr_err("__intel_gt_reset failed under %s\n", p->name);
290 /* As we poke around the guts, do a full reset before continuing. */
294 igt_global_reset_unlock(gt);
300 static int igt_atomic_engine_reset(void *arg)
302 struct intel_gt *gt = arg;
303 const typeof(*igt_atomic_phases) *p;
304 struct intel_engine_cs *engine;
305 enum intel_engine_id id;
308 /* Check that the resets are usable from atomic context */
310 if (!intel_has_reset_engine(gt))
313 if (intel_uc_uses_guc_submission(>->uc))
317 igt_global_reset_lock(gt);
319 /* Flush any requests before we get started and check basics */
320 if (!igt_force_reset(gt))
323 for_each_engine(engine, gt, id) {
324 struct tasklet_struct *t = &engine->sched_engine->tasklet;
328 intel_engine_pm_get(engine);
330 for (p = igt_atomic_phases; p->name; p++) {
331 GEM_TRACE("intel_engine_reset(%s) under %s\n",
332 engine->name, p->name);
333 if (strcmp(p->name, "softirq"))
336 p->critical_section_begin();
337 err = __intel_engine_reset_bh(engine, NULL);
338 p->critical_section_end();
340 if (strcmp(p->name, "softirq"))
344 pr_err("intel_engine_reset(%s) failed under %s\n",
345 engine->name, p->name);
350 intel_engine_pm_put(engine);
353 tasklet_hi_schedule(t);
359 /* As we poke around the guts, do a full reset before continuing. */
363 igt_global_reset_unlock(gt);
369 int intel_reset_live_selftests(struct drm_i915_private *i915)
371 static const struct i915_subtest tests[] = {
372 SUBTEST(igt_global_reset), /* attempt to recover GPU first */
373 SUBTEST(igt_reset_device_stolen),
374 SUBTEST(igt_reset_engines_stolen),
375 SUBTEST(igt_wedged_reset),
376 SUBTEST(igt_atomic_reset),
377 SUBTEST(igt_atomic_engine_reset),
379 struct intel_gt *gt = &i915->gt;
381 if (!intel_has_gpu_reset(gt))
384 if (intel_gt_is_wedged(gt))
385 return -EIO; /* we're long past hope of a successful reset */
387 return intel_gt_live_subtests(tests, gt);