This source file includes following definitions.
- available_dbs
- check_all_doorbells
- ring_doorbell_nop
- validate_client
- client_doorbell_in_sync
- igt_guc_clients
- igt_guc_doorbells
- intel_guc_live_selftest
1
2
3
4
5
6 #include "i915_selftest.h"
7 #include "gem/i915_gem_pm.h"
8
9
10 #define ATTEMPTS (GUC_NUM_DOORBELLS + GUC_CLIENT_PRIORITY_NUM)
11
12 static struct intel_guc_client *clients[ATTEMPTS];
13
14 static bool available_dbs(struct intel_guc *guc, u32 priority)
15 {
16 unsigned long offset;
17 unsigned long end;
18 u16 id;
19
20
21 offset = 0;
22 end = GUC_NUM_DOORBELLS / 2;
23 if (priority <= GUC_CLIENT_PRIORITY_HIGH) {
24 offset = end;
25 end += offset;
26 }
27
28 id = find_next_zero_bit(guc->doorbell_bitmap, end, offset);
29 if (id < end)
30 return true;
31
32 return false;
33 }
34
35 static int check_all_doorbells(struct intel_guc *guc)
36 {
37 u16 db_id;
38
39 pr_info_once("Max number of doorbells: %d", GUC_NUM_DOORBELLS);
40 for (db_id = 0; db_id < GUC_NUM_DOORBELLS; ++db_id) {
41 if (!doorbell_ok(guc, db_id)) {
42 pr_err("doorbell %d, not ok\n", db_id);
43 return -EIO;
44 }
45 }
46
47 return 0;
48 }
49
50 static int ring_doorbell_nop(struct intel_guc_client *client)
51 {
52 struct guc_process_desc *desc = __get_process_desc(client);
53 int err;
54
55 client->use_nop_wqi = true;
56
57 spin_lock_irq(&client->wq_lock);
58
59 guc_wq_item_append(client, 0, 0, 0, 0);
60 guc_ring_doorbell(client);
61
62 spin_unlock_irq(&client->wq_lock);
63
64 client->use_nop_wqi = false;
65
66
67
68
69 err = wait_for(READ_ONCE(desc->head) == READ_ONCE(desc->tail), 10);
70 if (err) {
71 pr_err("doorbell %u ring failed!\n", client->doorbell_id);
72 return -EIO;
73 }
74
75 if (desc->wq_status != WQ_STATUS_ACTIVE) {
76 pr_err("doorbell %u ring put WQ in bad state (%u)!\n",
77 client->doorbell_id, desc->wq_status);
78 return -EIO;
79 }
80
81 return 0;
82 }
83
84
85
86
87 static int validate_client(struct intel_guc_client *client, int client_priority)
88 {
89 if (client->priority != client_priority ||
90 client->doorbell_id == GUC_DOORBELL_INVALID)
91 return -EINVAL;
92 else
93 return 0;
94 }
95
96 static bool client_doorbell_in_sync(struct intel_guc_client *client)
97 {
98 return !client || doorbell_ok(client->guc, client->doorbell_id);
99 }
100
101
102
103
104
105
106
107
108
109
110
111 static int igt_guc_clients(void *args)
112 {
113 struct drm_i915_private *dev_priv = args;
114 intel_wakeref_t wakeref;
115 struct intel_guc *guc;
116 int err = 0;
117
118 GEM_BUG_ON(!HAS_GT_UC(dev_priv));
119 mutex_lock(&dev_priv->drm.struct_mutex);
120 wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
121
122 guc = &dev_priv->gt.uc.guc;
123 if (!guc) {
124 pr_err("No guc object!\n");
125 err = -EINVAL;
126 goto unlock;
127 }
128
129 err = check_all_doorbells(guc);
130 if (err)
131 goto unlock;
132
133
134
135
136
137 guc_clients_disable(guc);
138 guc_clients_destroy(guc);
139 if (guc->execbuf_client) {
140 pr_err("guc_clients_destroy lied!\n");
141 err = -EINVAL;
142 goto unlock;
143 }
144
145 err = guc_clients_create(guc);
146 if (err) {
147 pr_err("Failed to create clients\n");
148 goto unlock;
149 }
150 GEM_BUG_ON(!guc->execbuf_client);
151
152 err = validate_client(guc->execbuf_client,
153 GUC_CLIENT_PRIORITY_KMD_NORMAL);
154 if (err) {
155 pr_err("execbug client validation failed\n");
156 goto out;
157 }
158
159
160 if (!has_doorbell(guc->execbuf_client)) {
161 pr_err("guc_clients_create didn't reserve doorbells\n");
162 err = -EINVAL;
163 goto out;
164 }
165
166
167 guc_clients_enable(guc);
168
169
170 if (!client_doorbell_in_sync(guc->execbuf_client)) {
171 pr_err("failed to initialize the doorbells\n");
172 err = -EINVAL;
173 goto out;
174 }
175
176
177
178
179
180 err = create_doorbell(guc->execbuf_client);
181
182 out:
183
184
185
186
187 guc_clients_disable(guc);
188 guc_clients_destroy(guc);
189 guc_clients_create(guc);
190 guc_clients_enable(guc);
191 unlock:
192 intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
193 mutex_unlock(&dev_priv->drm.struct_mutex);
194 return err;
195 }
196
197
198
199
200
201
202 static int igt_guc_doorbells(void *arg)
203 {
204 struct drm_i915_private *dev_priv = arg;
205 intel_wakeref_t wakeref;
206 struct intel_guc *guc;
207 int i, err = 0;
208 u16 db_id;
209
210 GEM_BUG_ON(!HAS_GT_UC(dev_priv));
211 mutex_lock(&dev_priv->drm.struct_mutex);
212 wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
213
214 guc = &dev_priv->gt.uc.guc;
215 if (!guc) {
216 pr_err("No guc object!\n");
217 err = -EINVAL;
218 goto unlock;
219 }
220
221 err = check_all_doorbells(guc);
222 if (err)
223 goto unlock;
224
225 for (i = 0; i < ATTEMPTS; i++) {
226 clients[i] = guc_client_alloc(guc, i % GUC_CLIENT_PRIORITY_NUM);
227
228 if (!clients[i]) {
229 pr_err("[%d] No guc client\n", i);
230 err = -EINVAL;
231 goto out;
232 }
233
234 if (IS_ERR(clients[i])) {
235 if (PTR_ERR(clients[i]) != -ENOSPC) {
236 pr_err("[%d] unexpected error\n", i);
237 err = PTR_ERR(clients[i]);
238 goto out;
239 }
240
241 if (available_dbs(guc, i % GUC_CLIENT_PRIORITY_NUM)) {
242 pr_err("[%d] non-db related alloc fail\n", i);
243 err = -EINVAL;
244 goto out;
245 }
246
247
248 continue;
249 }
250
251
252
253
254
255 if (clients[i]->stage_id >= GUC_NUM_DOORBELLS) {
256 pr_err("[%d] more clients than doorbells (%d >= %d)\n",
257 i, clients[i]->stage_id, GUC_NUM_DOORBELLS);
258 err = -EINVAL;
259 goto out;
260 }
261
262 err = validate_client(clients[i], i % GUC_CLIENT_PRIORITY_NUM);
263 if (err) {
264 pr_err("[%d] client_alloc sanity check failed!\n", i);
265 err = -EINVAL;
266 goto out;
267 }
268
269 db_id = clients[i]->doorbell_id;
270
271 err = __guc_client_enable(clients[i]);
272 if (err) {
273 pr_err("[%d] Failed to create a doorbell\n", i);
274 goto out;
275 }
276
277
278 if (db_id != clients[i]->doorbell_id) {
279 pr_err("[%d] doorbell id changed (%d != %d)\n",
280 i, db_id, clients[i]->doorbell_id);
281 err = -EINVAL;
282 goto out;
283 }
284
285 err = check_all_doorbells(guc);
286 if (err)
287 goto out;
288
289 err = ring_doorbell_nop(clients[i]);
290 if (err)
291 goto out;
292 }
293
294 out:
295 for (i = 0; i < ATTEMPTS; i++)
296 if (!IS_ERR_OR_NULL(clients[i])) {
297 __guc_client_disable(clients[i]);
298 guc_client_free(clients[i]);
299 }
300 unlock:
301 intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
302 mutex_unlock(&dev_priv->drm.struct_mutex);
303 return err;
304 }
305
306 int intel_guc_live_selftest(struct drm_i915_private *dev_priv)
307 {
308 static const struct i915_subtest tests[] = {
309 SUBTEST(igt_guc_clients),
310 SUBTEST(igt_guc_doorbells),
311 };
312
313 if (!USES_GUC_SUBMISSION(dev_priv))
314 return 0;
315
316 return i915_subtests(tests, dev_priv);
317 }