1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2022 Intel Corporation 4 */ 5 6 #include "selftests/igt_spinner.h" 7 #include "selftests/igt_reset.h" 8 #include "selftests/intel_scheduler_helpers.h" 9 #include "gt/intel_engine_heartbeat.h" 10 #include "gem/selftests/mock_context.h" 11 12 #define BEAT_INTERVAL 100 13 14 static struct i915_request *nop_request(struct intel_engine_cs *engine) 15 { 16 struct i915_request *rq; 17 18 rq = intel_engine_create_kernel_request(engine); 19 if (IS_ERR(rq)) 20 return rq; 21 22 i915_request_get(rq); 23 i915_request_add(rq); 24 25 return rq; 26 } 27 28 static int intel_hang_guc(void *arg) 29 { 30 struct intel_gt *gt = arg; 31 int ret = 0; 32 struct i915_gem_context *ctx; 33 struct intel_context *ce; 34 struct igt_spinner spin; 35 struct i915_request *rq; 36 intel_wakeref_t wakeref; 37 struct i915_gpu_error *global = >->i915->gpu_error; 38 struct intel_engine_cs *engine; 39 unsigned int reset_count; 40 u32 guc_status; 41 u32 old_beat; 42 43 ctx = kernel_context(gt->i915, NULL); 44 if (IS_ERR(ctx)) { 45 drm_err(>->i915->drm, "Failed get kernel context: %ld\n", PTR_ERR(ctx)); 46 return PTR_ERR(ctx); 47 } 48 49 wakeref = intel_runtime_pm_get(gt->uncore->rpm); 50 51 ce = intel_context_create(gt->engine[BCS0]); 52 if (IS_ERR(ce)) { 53 ret = PTR_ERR(ce); 54 drm_err(>->i915->drm, "Failed to create spinner request: %d\n", ret); 55 goto err; 56 } 57 58 engine = ce->engine; 59 reset_count = i915_reset_count(global); 60 61 old_beat = engine->props.heartbeat_interval_ms; 62 ret = intel_engine_set_heartbeat(engine, BEAT_INTERVAL); 63 if (ret) { 64 drm_err(>->i915->drm, "Failed to boost heatbeat interval: %d\n", ret); 65 goto err; 66 } 67 68 ret = igt_spinner_init(&spin, engine->gt); 69 if (ret) { 70 drm_err(>->i915->drm, "Failed to create spinner: %d\n", ret); 71 goto err; 72 } 73 74 rq = igt_spinner_create_request(&spin, ce, MI_NOOP); 75 intel_context_put(ce); 76 if (IS_ERR(rq)) { 77 ret = PTR_ERR(rq); 78 drm_err(>->i915->drm, "Failed to create spinner request: %d\n", ret); 79 goto err_spin; 80 } 81 82 ret = request_add_spin(rq, &spin); 83 if (ret) { 84 i915_request_put(rq); 85 drm_err(>->i915->drm, "Failed to add Spinner request: %d\n", ret); 86 goto err_spin; 87 } 88 89 ret = intel_reset_guc(gt); 90 if (ret) { 91 i915_request_put(rq); 92 drm_err(>->i915->drm, "Failed to reset GuC, ret = %d\n", ret); 93 goto err_spin; 94 } 95 96 guc_status = intel_uncore_read(gt->uncore, GUC_STATUS); 97 if (!(guc_status & GS_MIA_IN_RESET)) { 98 i915_request_put(rq); 99 drm_err(>->i915->drm, "GuC failed to reset: status = 0x%08X\n", guc_status); 100 ret = -EIO; 101 goto err_spin; 102 } 103 104 /* Wait for the heartbeat to cause a reset */ 105 ret = intel_selftest_wait_for_rq(rq); 106 i915_request_put(rq); 107 if (ret) { 108 drm_err(>->i915->drm, "Request failed to complete: %d\n", ret); 109 goto err_spin; 110 } 111 112 if (i915_reset_count(global) == reset_count) { 113 drm_err(>->i915->drm, "Failed to record a GPU reset\n"); 114 ret = -EINVAL; 115 goto err_spin; 116 } 117 118 err_spin: 119 igt_spinner_end(&spin); 120 igt_spinner_fini(&spin); 121 intel_engine_set_heartbeat(engine, old_beat); 122 123 if (ret == 0) { 124 rq = nop_request(engine); 125 if (IS_ERR(rq)) { 126 ret = PTR_ERR(rq); 127 goto err; 128 } 129 130 ret = intel_selftest_wait_for_rq(rq); 131 i915_request_put(rq); 132 if (ret) { 133 drm_err(>->i915->drm, "No-op failed to complete: %d\n", ret); 134 goto err; 135 } 136 } 137 138 err: 139 intel_runtime_pm_put(gt->uncore->rpm, wakeref); 140 kernel_context_close(ctx); 141 142 return ret; 143 } 144 145 int intel_guc_hang_check(struct drm_i915_private *i915) 146 { 147 static const struct i915_subtest tests[] = { 148 SUBTEST(intel_hang_guc), 149 }; 150 struct intel_gt *gt = to_gt(i915); 151 152 if (intel_gt_is_wedged(gt)) 153 return 0; 154 155 if (!intel_uc_uses_guc_submission(>->uc)) 156 return 0; 157 158 return intel_gt_live_subtests(tests, gt); 159 } 160