1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright �� 2019 Intel Corporation
4 */
5
6 #include "gt/intel_gt_print.h"
7 #include "selftests/igt_spinner.h"
8 #include "selftests/igt_reset.h"
9 #include "selftests/intel_scheduler_helpers.h"
10 #include "gt/intel_engine_heartbeat.h"
11 #include "gem/selftests/mock_context.h"
12
logical_sort(struct intel_engine_cs ** engines,int num_engines)13 static void logical_sort(struct intel_engine_cs **engines, int num_engines)
14 {
15 struct intel_engine_cs *sorted[MAX_ENGINE_INSTANCE + 1];
16 int i, j;
17
18 for (i = 0; i < num_engines; ++i)
19 for (j = 0; j < MAX_ENGINE_INSTANCE + 1; ++j) {
20 if (engines[j]->logical_mask & BIT(i)) {
21 sorted[i] = engines[j];
22 break;
23 }
24 }
25
26 memcpy(*engines, *sorted,
27 sizeof(struct intel_engine_cs *) * num_engines);
28 }
29
30 static struct intel_context *
multi_lrc_create_parent(struct intel_gt * gt,u8 class,unsigned long flags)31 multi_lrc_create_parent(struct intel_gt *gt, u8 class,
32 unsigned long flags)
33 {
34 struct intel_engine_cs *siblings[MAX_ENGINE_INSTANCE + 1];
35 struct intel_engine_cs *engine;
36 enum intel_engine_id id;
37 int i = 0;
38
39 for_each_engine(engine, gt, id) {
40 if (engine->class != class)
41 continue;
42
43 siblings[i++] = engine;
44 }
45
46 if (i <= 1)
47 return ERR_PTR(0);
48
49 logical_sort(siblings, i);
50
51 return intel_engine_create_parallel(siblings, 1, i);
52 }
53
multi_lrc_context_unpin(struct intel_context * ce)54 static void multi_lrc_context_unpin(struct intel_context *ce)
55 {
56 struct intel_context *child;
57
58 GEM_BUG_ON(!intel_context_is_parent(ce));
59
60 for_each_child(ce, child)
61 intel_context_unpin(child);
62 intel_context_unpin(ce);
63 }
64
multi_lrc_context_put(struct intel_context * ce)65 static void multi_lrc_context_put(struct intel_context *ce)
66 {
67 GEM_BUG_ON(!intel_context_is_parent(ce));
68
69 /*
70 * Only the parent gets the creation ref put in the uAPI, the parent
71 * itself is responsible for creation ref put on the children.
72 */
73 intel_context_put(ce);
74 }
75
76 static struct i915_request *
multi_lrc_nop_request(struct intel_context * ce)77 multi_lrc_nop_request(struct intel_context *ce)
78 {
79 struct intel_context *child;
80 struct i915_request *rq, *child_rq;
81 int i = 0;
82
83 GEM_BUG_ON(!intel_context_is_parent(ce));
84
85 rq = intel_context_create_request(ce);
86 if (IS_ERR(rq))
87 return rq;
88
89 i915_request_get(rq);
90 i915_request_add(rq);
91
92 for_each_child(ce, child) {
93 child_rq = intel_context_create_request(child);
94 if (IS_ERR(child_rq))
95 goto child_error;
96
97 if (++i == ce->parallel.number_children)
98 set_bit(I915_FENCE_FLAG_SUBMIT_PARALLEL,
99 &child_rq->fence.flags);
100 i915_request_add(child_rq);
101 }
102
103 return rq;
104
105 child_error:
106 i915_request_put(rq);
107
108 return ERR_PTR(-ENOMEM);
109 }
110
__intel_guc_multi_lrc_basic(struct intel_gt * gt,unsigned int class)111 static int __intel_guc_multi_lrc_basic(struct intel_gt *gt, unsigned int class)
112 {
113 struct intel_context *parent;
114 struct i915_request *rq;
115 int ret;
116
117 parent = multi_lrc_create_parent(gt, class, 0);
118 if (IS_ERR(parent)) {
119 gt_err(gt, "Failed creating contexts: %pe\n", parent);
120 return PTR_ERR(parent);
121 } else if (!parent) {
122 gt_dbg(gt, "Not enough engines in class: %d\n", class);
123 return 0;
124 }
125
126 rq = multi_lrc_nop_request(parent);
127 if (IS_ERR(rq)) {
128 ret = PTR_ERR(rq);
129 gt_err(gt, "Failed creating requests: %pe\n", rq);
130 goto out;
131 }
132
133 ret = intel_selftest_wait_for_rq(rq);
134 if (ret)
135 gt_err(gt, "Failed waiting on request: %pe\n", ERR_PTR(ret));
136
137 i915_request_put(rq);
138
139 if (ret >= 0) {
140 ret = intel_gt_wait_for_idle(gt, HZ * 5);
141 if (ret < 0)
142 gt_err(gt, "GT failed to idle: %pe\n", ERR_PTR(ret));
143 }
144
145 out:
146 multi_lrc_context_unpin(parent);
147 multi_lrc_context_put(parent);
148 return ret;
149 }
150
intel_guc_multi_lrc_basic(void * arg)151 static int intel_guc_multi_lrc_basic(void *arg)
152 {
153 struct intel_gt *gt = arg;
154 unsigned int class;
155 int ret;
156
157 for (class = 0; class < MAX_ENGINE_CLASS + 1; ++class) {
158 /* We don't support breadcrumb handshake on these classes */
159 if (class == COMPUTE_CLASS || class == RENDER_CLASS)
160 continue;
161
162 ret = __intel_guc_multi_lrc_basic(gt, class);
163 if (ret)
164 return ret;
165 }
166
167 return 0;
168 }
169
intel_guc_multi_lrc_live_selftests(struct drm_i915_private * i915)170 int intel_guc_multi_lrc_live_selftests(struct drm_i915_private *i915)
171 {
172 static const struct i915_subtest tests[] = {
173 SUBTEST(intel_guc_multi_lrc_basic),
174 };
175 struct intel_gt *gt = to_gt(i915);
176
177 if (intel_gt_is_wedged(gt))
178 return 0;
179
180 if (!intel_uc_uses_guc_submission(>->uc))
181 return 0;
182
183 return intel_gt_live_subtests(tests, gt);
184 }
185