static struct i915_request * hang_create_request(struct hang *h, struct intel_engine_cs *engine) { struct i915_request *rq; int err; if (i915_gem_object_is_active(h->obj)) { struct drm_i915_gem_object *obj; void *vaddr; obj = i915_gem_object_create_internal(h->i915, PAGE_SIZE); if (IS_ERR(obj)) return ERR_CAST(obj); vaddr = i915_gem_object_pin_map(obj, i915_coherent_map_type(h->i915)); if (IS_ERR(vaddr)) { i915_gem_object_put(obj); return ERR_CAST(vaddr); } i915_gem_object_unpin_map(h->obj); i915_gem_object_put(h->obj); h->obj = obj; h->batch = vaddr; } rq = i915_request_alloc(engine, h->ctx); if (IS_ERR(rq)) return rq; err = emit_recurse_batch(h, rq); if (err) { i915_request_add(rq); return ERR_PTR(err); } return rq; }
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; }
static int igt_hang_sanitycheck(void *arg) { struct drm_i915_private *i915 = arg; struct i915_request *rq; struct intel_engine_cs *engine; enum intel_engine_id id; struct hang h; int err; /* Basic check that we can execute our hanging batch */ mutex_lock(&i915->drm.struct_mutex); err = hang_init(&h, i915); if (err) goto unlock; for_each_engine(engine, i915, id) { struct igt_wedge_me w; long timeout; if (!intel_engine_can_store_dword(engine)) continue; rq = hang_create_request(&h, engine); if (IS_ERR(rq)) { err = PTR_ERR(rq); pr_err("Failed to create request for %s, err=%d\n", engine->name, err); goto fini; } i915_request_get(rq); *h.batch = MI_BATCH_BUFFER_END; i915_gem_chipset_flush(i915); i915_request_add(rq); timeout = 0; igt_wedge_on_timeout(&w, i915, HZ / 10 /* 100ms timeout*/) timeout = i915_request_wait(rq, I915_WAIT_LOCKED, MAX_SCHEDULE_TIMEOUT); if (i915_terminally_wedged(&i915->gpu_error)) timeout = -EIO; i915_request_put(rq); if (timeout < 0) { err = timeout; pr_err("Wait for request failed on %s, err=%d\n", engine->name, err); goto fini; } } fini: hang_fini(&h); unlock: mutex_unlock(&i915->drm.struct_mutex); return err; }
struct i915_request * igt_spinner_create_request(struct igt_spinner *spin, struct i915_gem_context *ctx, struct intel_engine_cs *engine, u32 arbitration_command) { struct i915_address_space *vm = &ctx->ppgtt->vm; struct i915_request *rq = NULL; struct i915_vma *hws, *vma; u32 *batch; int err; vma = i915_vma_instance(spin->obj, vm, NULL); if (IS_ERR(vma)) return ERR_CAST(vma); hws = i915_vma_instance(spin->hws, vm, NULL); if (IS_ERR(hws)) return ERR_CAST(hws); err = i915_vma_pin(vma, 0, 0, PIN_USER); if (err) return ERR_PTR(err); err = i915_vma_pin(hws, 0, 0, PIN_USER); if (err) goto unpin_vma; rq = i915_request_alloc(engine, ctx); if (IS_ERR(rq)) { err = PTR_ERR(rq); goto unpin_hws; } err = move_to_active(vma, rq, 0); if (err) goto cancel_rq; err = move_to_active(hws, rq, 0); if (err) goto cancel_rq; batch = spin->batch; *batch++ = MI_STORE_DWORD_IMM_GEN4; *batch++ = lower_32_bits(hws_address(hws, rq)); *batch++ = upper_32_bits(hws_address(hws, rq)); *batch++ = rq->fence.seqno; *batch++ = arbitration_command; *batch++ = MI_BATCH_BUFFER_START | 1 << 8 | 1; *batch++ = lower_32_bits(vma->node.start); *batch++ = upper_32_bits(vma->node.start); *batch++ = MI_BATCH_BUFFER_END; /* not reached */ i915_gem_chipset_flush(spin->i915); err = engine->emit_bb_start(rq, vma->node.start, PAGE_SIZE, 0); cancel_rq: if (err) { i915_request_skip(rq, err); i915_request_add(rq); } unpin_hws: i915_vma_unpin(hws); unpin_vma: i915_vma_unpin(vma); return err ? ERR_PTR(err) : rq; }