selftest_reset.c (8459B)
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 = >->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; 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_CACHE_NONE, 0); 90 mb(); 91 92 s = io_mapping_map_wc(&ggtt->iomap, 93 ggtt->error_capture.start, 94 PAGE_SIZE); 95 96 if (!__drm_mm_interval_first(>->i915->mm.stolen, 97 page << PAGE_SHIFT, 98 ((page + 1) << PAGE_SHIFT) - 1)) 99 memset_io(s, STACK_MAGIC, PAGE_SIZE); 100 101 in = (void __force *)s; 102 if (i915_memcpy_from_wc(tmp, in, PAGE_SIZE)) 103 in = tmp; 104 crc[page] = crc32_le(0, in, PAGE_SIZE); 105 106 io_mapping_unmap(s); 107 } 108 mb(); 109 ggtt->vm.clear_range(&ggtt->vm, ggtt->error_capture.start, PAGE_SIZE); 110 111 if (mask == ALL_ENGINES) { 112 intel_gt_reset(gt, mask, NULL); 113 } else { 114 for_each_engine(engine, gt, id) { 115 if (mask & engine->mask) 116 intel_engine_reset(engine, NULL); 117 } 118 } 119 120 max = -1; 121 count = 0; 122 for (page = 0; page < num_pages; page++) { 123 dma_addr_t dma = (dma_addr_t)dsm->start + (page << PAGE_SHIFT); 124 void __iomem *s; 125 void *in; 126 u32 x; 127 128 ggtt->vm.insert_page(&ggtt->vm, dma, 129 ggtt->error_capture.start, 130 I915_CACHE_NONE, 0); 131 mb(); 132 133 s = io_mapping_map_wc(&ggtt->iomap, 134 ggtt->error_capture.start, 135 PAGE_SIZE); 136 137 in = (void __force *)s; 138 if (i915_memcpy_from_wc(tmp, in, PAGE_SIZE)) 139 in = tmp; 140 x = crc32_le(0, in, PAGE_SIZE); 141 142 if (x != crc[page] && 143 !__drm_mm_interval_first(>->i915->mm.stolen, 144 page << PAGE_SHIFT, 145 ((page + 1) << PAGE_SHIFT) - 1)) { 146 pr_debug("unused stolen page %pa modified by GPU reset\n", 147 &page); 148 if (count++ == 0) 149 igt_hexdump(in, PAGE_SIZE); 150 max = page; 151 } 152 153 io_mapping_unmap(s); 154 } 155 mb(); 156 ggtt->vm.clear_range(&ggtt->vm, ggtt->error_capture.start, PAGE_SIZE); 157 158 if (count > 0) { 159 pr_info("%s reset clobbered %ld pages of stolen, last clobber at page %ld\n", 160 msg, count, max); 161 } 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); 165 err = -EINVAL; 166 } 167 168err_spin: 169 igt_spinner_fini(&spin); 170 171err_lock: 172 intel_runtime_pm_put(gt->uncore->rpm, wakeref); 173 igt_global_reset_unlock(gt); 174 175 kfree(tmp); 176err_crc: 177 kfree(crc); 178 return err; 179} 180 181static int igt_reset_device_stolen(void *arg) 182{ 183 return __igt_reset_stolen(arg, ALL_ENGINES, "device"); 184} 185 186static int igt_reset_engines_stolen(void *arg) 187{ 188 struct intel_gt *gt = arg; 189 struct intel_engine_cs *engine; 190 enum intel_engine_id id; 191 int err; 192 193 if (!intel_has_reset_engine(gt)) 194 return 0; 195 196 for_each_engine(engine, gt, id) { 197 err = __igt_reset_stolen(gt, engine->mask, engine->name); 198 if (err) 199 return err; 200 } 201 202 return 0; 203} 204 205static int igt_global_reset(void *arg) 206{ 207 struct intel_gt *gt = arg; 208 unsigned int reset_count; 209 intel_wakeref_t wakeref; 210 int err = 0; 211 212 /* Check that we can issue a global GPU reset */ 213 214 igt_global_reset_lock(gt); 215 wakeref = intel_runtime_pm_get(gt->uncore->rpm); 216 217 reset_count = i915_reset_count(>->i915->gpu_error); 218 219 intel_gt_reset(gt, ALL_ENGINES, NULL); 220 221 if (i915_reset_count(>->i915->gpu_error) == reset_count) { 222 pr_err("No GPU reset recorded!\n"); 223 err = -EINVAL; 224 } 225 226 intel_runtime_pm_put(gt->uncore->rpm, wakeref); 227 igt_global_reset_unlock(gt); 228 229 if (intel_gt_is_wedged(gt)) 230 err = -EIO; 231 232 return err; 233} 234 235static int igt_wedged_reset(void *arg) 236{ 237 struct intel_gt *gt = arg; 238 intel_wakeref_t wakeref; 239 240 /* Check that we can recover a wedged device with a GPU reset */ 241 242 igt_global_reset_lock(gt); 243 wakeref = intel_runtime_pm_get(gt->uncore->rpm); 244 245 intel_gt_set_wedged(gt); 246 247 GEM_BUG_ON(!intel_gt_is_wedged(gt)); 248 intel_gt_reset(gt, ALL_ENGINES, NULL); 249 250 intel_runtime_pm_put(gt->uncore->rpm, wakeref); 251 igt_global_reset_unlock(gt); 252 253 return intel_gt_is_wedged(gt) ? -EIO : 0; 254} 255 256static int igt_atomic_reset(void *arg) 257{ 258 struct intel_gt *gt = arg; 259 const typeof(*igt_atomic_phases) *p; 260 int err = 0; 261 262 /* Check that the resets are usable from atomic context */ 263 264 intel_gt_pm_get(gt); 265 igt_global_reset_lock(gt); 266 267 /* Flush any requests before we get started and check basics */ 268 if (!igt_force_reset(gt)) 269 goto unlock; 270 271 for (p = igt_atomic_phases; p->name; p++) { 272 intel_engine_mask_t awake; 273 274 GEM_TRACE("__intel_gt_reset under %s\n", p->name); 275 276 awake = reset_prepare(gt); 277 p->critical_section_begin(); 278 279 err = __intel_gt_reset(gt, ALL_ENGINES); 280 281 p->critical_section_end(); 282 reset_finish(gt, awake); 283 284 if (err) { 285 pr_err("__intel_gt_reset failed under %s\n", p->name); 286 break; 287 } 288 } 289 290 /* As we poke around the guts, do a full reset before continuing. */ 291 igt_force_reset(gt); 292 293unlock: 294 igt_global_reset_unlock(gt); 295 intel_gt_pm_put(gt); 296 297 return err; 298} 299 300static int igt_atomic_engine_reset(void *arg) 301{ 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; 306 int err = 0; 307 308 /* Check that the resets are usable from atomic context */ 309 310 if (!intel_has_reset_engine(gt)) 311 return 0; 312 313 if (intel_uc_uses_guc_submission(>->uc)) 314 return 0; 315 316 intel_gt_pm_get(gt); 317 igt_global_reset_lock(gt); 318 319 /* Flush any requests before we get started and check basics */ 320 if (!igt_force_reset(gt)) 321 goto out_unlock; 322 323 for_each_engine(engine, gt, id) { 324 struct tasklet_struct *t = &engine->sched_engine->tasklet; 325 326 if (t->func) 327 tasklet_disable(t); 328 intel_engine_pm_get(engine); 329 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")) 334 local_bh_disable(); 335 336 p->critical_section_begin(); 337 err = __intel_engine_reset_bh(engine, NULL); 338 p->critical_section_end(); 339 340 if (strcmp(p->name, "softirq")) 341 local_bh_enable(); 342 343 if (err) { 344 pr_err("intel_engine_reset(%s) failed under %s\n", 345 engine->name, p->name); 346 break; 347 } 348 } 349 350 intel_engine_pm_put(engine); 351 if (t->func) { 352 tasklet_enable(t); 353 tasklet_hi_schedule(t); 354 } 355 if (err) 356 break; 357 } 358 359 /* As we poke around the guts, do a full reset before continuing. */ 360 igt_force_reset(gt); 361 362out_unlock: 363 igt_global_reset_unlock(gt); 364 intel_gt_pm_put(gt); 365 366 return err; 367} 368 369int intel_reset_live_selftests(struct drm_i915_private *i915) 370{ 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), 378 }; 379 struct intel_gt *gt = to_gt(i915); 380 381 if (!intel_has_gpu_reset(gt)) 382 return 0; 383 384 if (intel_gt_is_wedged(gt)) 385 return -EIO; /* we're long past hope of a successful reset */ 386 387 return intel_gt_live_subtests(tests, gt); 388}