int igt_live_test_end(struct igt_live_test *t) { struct drm_i915_private *i915 = t->i915; struct intel_engine_cs *engine; enum intel_engine_id id; lockdep_assert_held(&i915->drm.struct_mutex); if (igt_flush_test(i915, I915_WAIT_LOCKED)) return -EIO; if (t->reset_global != i915_reset_count(&i915->gpu_error)) { pr_err("%s(%s): GPU was reset %d times!\n", t->func, t->name, i915_reset_count(&i915->gpu_error) - t->reset_global); return -EIO; } for_each_engine(engine, i915, id) { if (t->reset_engine[id] == i915_reset_engine_count(&i915->gpu_error, engine)) continue; pr_err("%s(%s): engine '%s' was reset %d times!\n", t->func, t->name, engine->name, i915_reset_engine_count(&i915->gpu_error, engine) - t->reset_engine[id]); return -EIO; } return 0; }
static void hang_fini(struct hang *h) { *h->batch = MI_BATCH_BUFFER_END; i915_gem_chipset_flush(h->i915); i915_gem_object_unpin_map(h->obj); i915_gem_object_put(h->obj); i915_gem_object_unpin_map(h->hws); i915_gem_object_put(h->hws); kernel_context_close(h->ctx); igt_flush_test(h->i915, I915_WAIT_LOCKED); }
static int __igt_reset_engine(struct drm_i915_private *i915, bool active) { struct intel_engine_cs *engine; enum intel_engine_id id; struct hang h; int err = 0; /* Check that we can issue an engine reset on an idle engine (no-op) */ if (!intel_has_reset_engine(i915)) return 0; if (active) { mutex_lock(&i915->drm.struct_mutex); err = hang_init(&h, i915); mutex_unlock(&i915->drm.struct_mutex); if (err) return err; } for_each_engine(engine, i915, id) { unsigned int reset_count, reset_engine_count; IGT_TIMEOUT(end_time); if (active && !intel_engine_can_store_dword(engine)) continue; if (!wait_for_idle(engine)) { pr_err("%s failed to idle before reset\n", engine->name); err = -EIO; break; } reset_count = i915_reset_count(&i915->gpu_error); reset_engine_count = i915_reset_engine_count(&i915->gpu_error, engine); set_bit(I915_RESET_ENGINE + id, &i915->gpu_error.flags); do { u32 seqno = intel_engine_get_seqno(engine); if (active) { struct i915_request *rq; mutex_lock(&i915->drm.struct_mutex); rq = hang_create_request(&h, engine); if (IS_ERR(rq)) { err = PTR_ERR(rq); mutex_unlock(&i915->drm.struct_mutex); break; } i915_request_get(rq); i915_request_add(rq); mutex_unlock(&i915->drm.struct_mutex); if (!wait_until_running(&h, rq)) { struct drm_printer p = drm_info_printer(i915->drm.dev); pr_err("%s: Failed to start request %x, at %x\n", __func__, rq->fence.seqno, hws_seqno(&h, rq)); intel_engine_dump(engine, &p, "%s\n", engine->name); i915_request_put(rq); err = -EIO; break; } GEM_BUG_ON(!rq->global_seqno); seqno = rq->global_seqno - 1; i915_request_put(rq); } err = i915_reset_engine(engine, NULL); if (err) { pr_err("i915_reset_engine failed\n"); break; } if (i915_reset_count(&i915->gpu_error) != reset_count) { pr_err("Full GPU reset recorded! (engine reset expected)\n"); err = -EINVAL; break; } reset_engine_count += active; if (i915_reset_engine_count(&i915->gpu_error, engine) != reset_engine_count) { pr_err("%s engine reset %srecorded!\n", engine->name, active ? "not " : ""); err = -EINVAL; break; } if (!wait_for_idle(engine)) { struct drm_printer p = drm_info_printer(i915->drm.dev); pr_err("%s failed to idle after reset\n", engine->name); intel_engine_dump(engine, &p, "%s\n", engine->name); err = -EIO; break; } } while (time_before(jiffies, end_time)); clear_bit(I915_RESET_ENGINE + id, &i915->gpu_error.flags); if (err) break; err = igt_flush_test(i915, 0); if (err) break; }