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
nop_request(struct intel_engine_cs * engine)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
intel_hang_guc(void * arg)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
intel_guc_hang_check(struct drm_i915_private * i915)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