GNU Linux-libre 4.19.264-gnu1
[releases.git] / drivers / gpu / drm / i915 / selftests / intel_guc.c
1 /*
2  * Copyright © 2017 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  */
24
25 #include "../i915_selftest.h"
26
27 /* max doorbell number + negative test for each client type */
28 #define ATTEMPTS (GUC_NUM_DOORBELLS + GUC_CLIENT_PRIORITY_NUM)
29
30 static struct intel_guc_client *clients[ATTEMPTS];
31
32 static bool available_dbs(struct intel_guc *guc, u32 priority)
33 {
34         unsigned long offset;
35         unsigned long end;
36         u16 id;
37
38         /* first half is used for normal priority, second half for high */
39         offset = 0;
40         end = GUC_NUM_DOORBELLS / 2;
41         if (priority <= GUC_CLIENT_PRIORITY_HIGH) {
42                 offset = end;
43                 end += offset;
44         }
45
46         id = find_next_zero_bit(guc->doorbell_bitmap, end, offset);
47         if (id < end)
48                 return true;
49
50         return false;
51 }
52
53 static int check_all_doorbells(struct intel_guc *guc)
54 {
55         u16 db_id;
56
57         pr_info_once("Max number of doorbells: %d", GUC_NUM_DOORBELLS);
58         for (db_id = 0; db_id < GUC_NUM_DOORBELLS; ++db_id) {
59                 if (!doorbell_ok(guc, db_id)) {
60                         pr_err("doorbell %d, not ok\n", db_id);
61                         return -EIO;
62                 }
63         }
64
65         return 0;
66 }
67
68 /*
69  * Basic client sanity check, handy to validate create_clients.
70  */
71 static int validate_client(struct intel_guc_client *client,
72                            int client_priority,
73                            bool is_preempt_client)
74 {
75         struct drm_i915_private *dev_priv = guc_to_i915(client->guc);
76         struct i915_gem_context *ctx_owner = is_preempt_client ?
77                         dev_priv->preempt_context : dev_priv->kernel_context;
78
79         if (client->owner != ctx_owner ||
80             client->engines != INTEL_INFO(dev_priv)->ring_mask ||
81             client->priority != client_priority ||
82             client->doorbell_id == GUC_DOORBELL_INVALID)
83                 return -EINVAL;
84         else
85                 return 0;
86 }
87
88 static bool client_doorbell_in_sync(struct intel_guc_client *client)
89 {
90         return !client || doorbell_ok(client->guc, client->doorbell_id);
91 }
92
93 /*
94  * Check that we're able to synchronize guc_clients with their doorbells
95  *
96  * We're creating clients and reserving doorbells once, at module load. During
97  * module lifetime, GuC, doorbell HW, and i915 state may go out of sync due to
98  * GuC being reset. In other words - GuC clients are still around, but the
99  * status of their doorbells may be incorrect. This is the reason behind
100  * validating that the doorbells status expected by the driver matches what the
101  * GuC/HW have.
102  */
103 static int igt_guc_clients(void *args)
104 {
105         struct drm_i915_private *dev_priv = args;
106         struct intel_guc *guc;
107         int err = 0;
108
109         GEM_BUG_ON(!HAS_GUC(dev_priv));
110         mutex_lock(&dev_priv->drm.struct_mutex);
111
112         guc = &dev_priv->guc;
113         if (!guc) {
114                 pr_err("No guc object!\n");
115                 err = -EINVAL;
116                 goto unlock;
117         }
118
119         err = check_all_doorbells(guc);
120         if (err)
121                 goto unlock;
122
123         /*
124          * Get rid of clients created during driver load because the test will
125          * recreate them.
126          */
127         guc_clients_destroy(guc);
128         if (guc->execbuf_client || guc->preempt_client) {
129                 pr_err("guc_clients_destroy lied!\n");
130                 err = -EINVAL;
131                 goto unlock;
132         }
133
134         err = guc_clients_create(guc);
135         if (err) {
136                 pr_err("Failed to create clients\n");
137                 goto unlock;
138         }
139         GEM_BUG_ON(!guc->execbuf_client);
140
141         err = validate_client(guc->execbuf_client,
142                               GUC_CLIENT_PRIORITY_KMD_NORMAL, false);
143         if (err) {
144                 pr_err("execbug client validation failed\n");
145                 goto out;
146         }
147
148         if (guc->preempt_client) {
149                 err = validate_client(guc->preempt_client,
150                                       GUC_CLIENT_PRIORITY_KMD_HIGH, true);
151                 if (err) {
152                         pr_err("preempt client validation failed\n");
153                         goto out;
154                 }
155         }
156
157         /* each client should now have reserved a doorbell */
158         if (!has_doorbell(guc->execbuf_client) ||
159             (guc->preempt_client && !has_doorbell(guc->preempt_client))) {
160                 pr_err("guc_clients_create didn't reserve doorbells\n");
161                 err = -EINVAL;
162                 goto out;
163         }
164
165         /* Now create the doorbells */
166         guc_clients_doorbell_init(guc);
167
168         /* each client should now have received a doorbell */
169         if (!client_doorbell_in_sync(guc->execbuf_client) ||
170             !client_doorbell_in_sync(guc->preempt_client)) {
171                 pr_err("failed to initialize the doorbells\n");
172                 err = -EINVAL;
173                 goto out;
174         }
175
176         /*
177          * Basic test - an attempt to reallocate a valid doorbell to the
178          * client it is currently assigned should not cause a failure.
179          */
180         err = guc_clients_doorbell_init(guc);
181         if (err)
182                 goto out;
183
184         /*
185          * Negative test - a client with no doorbell (invalid db id).
186          * After destroying the doorbell, the db id is changed to
187          * GUC_DOORBELL_INVALID and the firmware will reject any attempt to
188          * allocate a doorbell with an invalid id (db has to be reserved before
189          * allocation).
190          */
191         destroy_doorbell(guc->execbuf_client);
192         if (client_doorbell_in_sync(guc->execbuf_client)) {
193                 pr_err("destroy db did not work\n");
194                 err = -EINVAL;
195                 goto out;
196         }
197
198         unreserve_doorbell(guc->execbuf_client);
199
200         __create_doorbell(guc->execbuf_client);
201         err = __guc_allocate_doorbell(guc, guc->execbuf_client->stage_id);
202         if (err != -EIO) {
203                 pr_err("unexpected (err = %d)", err);
204                 goto out_db;
205         }
206
207         if (!available_dbs(guc, guc->execbuf_client->priority)) {
208                 pr_err("doorbell not available when it should\n");
209                 err = -EIO;
210                 goto out_db;
211         }
212
213 out_db:
214         /* clean after test */
215         __destroy_doorbell(guc->execbuf_client);
216         err = reserve_doorbell(guc->execbuf_client);
217         if (err) {
218                 pr_err("failed to reserve back the doorbell back\n");
219         }
220         err = create_doorbell(guc->execbuf_client);
221         if (err) {
222                 pr_err("recreate doorbell failed\n");
223                 goto out;
224         }
225
226 out:
227         /*
228          * Leave clean state for other test, plus the driver always destroy the
229          * clients during unload.
230          */
231         destroy_doorbell(guc->execbuf_client);
232         if (guc->preempt_client)
233                 destroy_doorbell(guc->preempt_client);
234         guc_clients_destroy(guc);
235         guc_clients_create(guc);
236         guc_clients_doorbell_init(guc);
237 unlock:
238         mutex_unlock(&dev_priv->drm.struct_mutex);
239         return err;
240 }
241
242 /*
243  * Create as many clients as number of doorbells. Note that there's already
244  * client(s)/doorbell(s) created during driver load, but this test creates
245  * its own and do not interact with the existing ones.
246  */
247 static int igt_guc_doorbells(void *arg)
248 {
249         struct drm_i915_private *dev_priv = arg;
250         struct intel_guc *guc;
251         int i, err = 0;
252         u16 db_id;
253
254         GEM_BUG_ON(!HAS_GUC(dev_priv));
255         mutex_lock(&dev_priv->drm.struct_mutex);
256
257         guc = &dev_priv->guc;
258         if (!guc) {
259                 pr_err("No guc object!\n");
260                 err = -EINVAL;
261                 goto unlock;
262         }
263
264         err = check_all_doorbells(guc);
265         if (err)
266                 goto unlock;
267
268         for (i = 0; i < ATTEMPTS; i++) {
269                 clients[i] = guc_client_alloc(dev_priv,
270                                               INTEL_INFO(dev_priv)->ring_mask,
271                                               i % GUC_CLIENT_PRIORITY_NUM,
272                                               dev_priv->kernel_context);
273
274                 if (!clients[i]) {
275                         pr_err("[%d] No guc client\n", i);
276                         err = -EINVAL;
277                         goto out;
278                 }
279
280                 if (IS_ERR(clients[i])) {
281                         if (PTR_ERR(clients[i]) != -ENOSPC) {
282                                 pr_err("[%d] unexpected error\n", i);
283                                 err = PTR_ERR(clients[i]);
284                                 goto out;
285                         }
286
287                         if (available_dbs(guc, i % GUC_CLIENT_PRIORITY_NUM)) {
288                                 pr_err("[%d] non-db related alloc fail\n", i);
289                                 err = -EINVAL;
290                                 goto out;
291                         }
292
293                         /* expected, ran out of dbs for this client type */
294                         continue;
295                 }
296
297                 /*
298                  * The check below is only valid because we keep a doorbell
299                  * assigned during the whole life of the client.
300                  */
301                 if (clients[i]->stage_id >= GUC_NUM_DOORBELLS) {
302                         pr_err("[%d] more clients than doorbells (%d >= %d)\n",
303                                i, clients[i]->stage_id, GUC_NUM_DOORBELLS);
304                         err = -EINVAL;
305                         goto out;
306                 }
307
308                 err = validate_client(clients[i],
309                                       i % GUC_CLIENT_PRIORITY_NUM, false);
310                 if (err) {
311                         pr_err("[%d] client_alloc sanity check failed!\n", i);
312                         err = -EINVAL;
313                         goto out;
314                 }
315
316                 db_id = clients[i]->doorbell_id;
317
318                 err = create_doorbell(clients[i]);
319                 if (err) {
320                         pr_err("[%d] Failed to create a doorbell\n", i);
321                         goto out;
322                 }
323
324                 /* doorbell id shouldn't change, we are holding the mutex */
325                 if (db_id != clients[i]->doorbell_id) {
326                         pr_err("[%d] doorbell id changed (%d != %d)\n",
327                                i, db_id, clients[i]->doorbell_id);
328                         err = -EINVAL;
329                         goto out;
330                 }
331
332                 err = check_all_doorbells(guc);
333                 if (err)
334                         goto out;
335         }
336
337 out:
338         for (i = 0; i < ATTEMPTS; i++)
339                 if (!IS_ERR_OR_NULL(clients[i])) {
340                         destroy_doorbell(clients[i]);
341                         guc_client_free(clients[i]);
342                 }
343 unlock:
344         mutex_unlock(&dev_priv->drm.struct_mutex);
345         return err;
346 }
347
348 int intel_guc_live_selftest(struct drm_i915_private *dev_priv)
349 {
350         static const struct i915_subtest tests[] = {
351                 SUBTEST(igt_guc_clients),
352                 SUBTEST(igt_guc_doorbells),
353         };
354
355         if (!USES_GUC_SUBMISSION(dev_priv))
356                 return 0;
357
358         return i915_subtests(tests, dev_priv);
359 }