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 = intel_selftest_find_any_engine(gt); 39 unsigned int reset_count; 40 u32 guc_status; 41 u32 old_beat; 42 43 if (!engine) 44 return 0; 45 46 ctx = kernel_context(gt->i915, NULL); 47 if (IS_ERR(ctx)) { 48 drm_err(>->i915->drm, "Failed get kernel context: %ld\n", PTR_ERR(ctx)); 49 return PTR_ERR(ctx); 50 } 51 52 wakeref = intel_runtime_pm_get(gt->uncore->rpm); 53 54 ce = intel_context_create(engine); 55 if (IS_ERR(ce)) { 56 ret = PTR_ERR(ce); 57 drm_err(>->i915->drm, "Failed to create spinner request: %d\n", ret); 58 goto err; 59 } 60 61 reset_count = i915_reset_count(global); 62 63 old_beat = engine->props.heartbeat_interval_ms; 64 ret = intel_engine_set_heartbeat(engine, BEAT_INTERVAL); 65 if (ret) { 66 drm_err(>->i915->drm, "Failed to boost heatbeat interval: %d\n", ret); 67 goto err; 68 } 69 70 ret = igt_spinner_init(&spin, engine->gt); 71 if (ret) { 72 drm_err(>->i915->drm, "Failed to create spinner: %d\n", ret); 73 goto err; 74 } 75 76 rq = igt_spinner_create_request(&spin, ce, MI_NOOP); 77 intel_context_put(ce); 78 if (IS_ERR(rq)) { 79 ret = PTR_ERR(rq); 80 drm_err(>->i915->drm, "Failed to create spinner request: %d\n", ret); 81 goto err_spin; 82 } 83 84 ret = request_add_spin(rq, &spin); 85 if (ret) { 86 i915_request_put(rq); 87 drm_err(>->i915->drm, "Failed to add Spinner request: %d\n", ret); 88 goto err_spin; 89 } 90 91 ret = intel_reset_guc(gt); 92 if (ret) { 93 i915_request_put(rq); 94 drm_err(>->i915->drm, "Failed to reset GuC, ret = %d\n", ret); 95 goto err_spin; 96 } 97 98 guc_status = intel_uncore_read(gt->uncore, GUC_STATUS); 99 if (!(guc_status & GS_MIA_IN_RESET)) { 100 i915_request_put(rq); 101 drm_err(>->i915->drm, "GuC failed to reset: status = 0x%08X\n", guc_status); 102 ret = -EIO; 103 goto err_spin; 104 } 105 106 /* Wait for the heartbeat to cause a reset */ 107 ret = intel_selftest_wait_for_rq(rq); 108 i915_request_put(rq); 109 if (ret) { 110 drm_err(>->i915->drm, "Request failed to complete: %d\n", ret); 111 goto err_spin; 112 } 113 114 if (i915_reset_count(global) == reset_count) { 115 drm_err(>->i915->drm, "Failed to record a GPU reset\n"); 116 ret = -EINVAL; 117 goto err_spin; 118 } 119 120 err_spin: 121 igt_spinner_end(&spin); 122 igt_spinner_fini(&spin); 123 intel_engine_set_heartbeat(engine, old_beat); 124 125 if (ret == 0) { 126 rq = nop_request(engine); 127 if (IS_ERR(rq)) { 128 ret = PTR_ERR(rq); 129 goto err; 130 } 131 132 ret = intel_selftest_wait_for_rq(rq); 133 i915_request_put(rq); 134 if (ret) { 135 drm_err(>->i915->drm, "No-op failed to complete: %d\n", ret); 136 goto err; 137 } 138 } 139 140 err: 141 intel_runtime_pm_put(gt->uncore->rpm, wakeref); 142 kernel_context_close(ctx); 143 144 return ret; 145 } 146 147 int intel_guc_hang_check(struct drm_i915_private *i915) 148 { 149 static const struct i915_subtest tests[] = { 150 SUBTEST(intel_hang_guc), 151 }; 152 struct intel_gt *gt = to_gt(i915); 153 154 if (intel_gt_is_wedged(gt)) 155 return 0; 156 157 if (!intel_uc_uses_guc_submission(>->uc)) 158 return 0; 159 160 return intel_gt_live_subtests(tests, gt); 161 } 162