]> Git Repo - linux.git/blob - drivers/gpu/drm/i915/selftests/intel_guc.c
Merge branch 'sched-wait-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux.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         err = guc_clients_doorbell_init(guc);
200         if (err != -EIO) {
201                 pr_err("unexpected (err = %d)", err);
202                 goto out;
203         }
204
205         if (!available_dbs(guc, guc->execbuf_client->priority)) {
206                 pr_err("doorbell not available when it should\n");
207                 err = -EIO;
208                 goto out;
209         }
210
211         /* clean after test */
212         err = reserve_doorbell(guc->execbuf_client);
213         if (err) {
214                 pr_err("failed to reserve back the doorbell back\n");
215         }
216         err = create_doorbell(guc->execbuf_client);
217         if (err) {
218                 pr_err("recreate doorbell failed\n");
219                 goto out;
220         }
221
222 out:
223         /*
224          * Leave clean state for other test, plus the driver always destroy the
225          * clients during unload.
226          */
227         destroy_doorbell(guc->execbuf_client);
228         if (guc->preempt_client)
229                 destroy_doorbell(guc->preempt_client);
230         guc_clients_destroy(guc);
231         guc_clients_create(guc);
232         guc_clients_doorbell_init(guc);
233 unlock:
234         mutex_unlock(&dev_priv->drm.struct_mutex);
235         return err;
236 }
237
238 /*
239  * Create as many clients as number of doorbells. Note that there's already
240  * client(s)/doorbell(s) created during driver load, but this test creates
241  * its own and do not interact with the existing ones.
242  */
243 static int igt_guc_doorbells(void *arg)
244 {
245         struct drm_i915_private *dev_priv = arg;
246         struct intel_guc *guc;
247         int i, err = 0;
248         u16 db_id;
249
250         GEM_BUG_ON(!HAS_GUC(dev_priv));
251         mutex_lock(&dev_priv->drm.struct_mutex);
252
253         guc = &dev_priv->guc;
254         if (!guc) {
255                 pr_err("No guc object!\n");
256                 err = -EINVAL;
257                 goto unlock;
258         }
259
260         err = check_all_doorbells(guc);
261         if (err)
262                 goto unlock;
263
264         for (i = 0; i < ATTEMPTS; i++) {
265                 clients[i] = guc_client_alloc(dev_priv,
266                                               INTEL_INFO(dev_priv)->ring_mask,
267                                               i % GUC_CLIENT_PRIORITY_NUM,
268                                               dev_priv->kernel_context);
269
270                 if (!clients[i]) {
271                         pr_err("[%d] No guc client\n", i);
272                         err = -EINVAL;
273                         goto out;
274                 }
275
276                 if (IS_ERR(clients[i])) {
277                         if (PTR_ERR(clients[i]) != -ENOSPC) {
278                                 pr_err("[%d] unexpected error\n", i);
279                                 err = PTR_ERR(clients[i]);
280                                 goto out;
281                         }
282
283                         if (available_dbs(guc, i % GUC_CLIENT_PRIORITY_NUM)) {
284                                 pr_err("[%d] non-db related alloc fail\n", i);
285                                 err = -EINVAL;
286                                 goto out;
287                         }
288
289                         /* expected, ran out of dbs for this client type */
290                         continue;
291                 }
292
293                 /*
294                  * The check below is only valid because we keep a doorbell
295                  * assigned during the whole life of the client.
296                  */
297                 if (clients[i]->stage_id >= GUC_NUM_DOORBELLS) {
298                         pr_err("[%d] more clients than doorbells (%d >= %d)\n",
299                                i, clients[i]->stage_id, GUC_NUM_DOORBELLS);
300                         err = -EINVAL;
301                         goto out;
302                 }
303
304                 err = validate_client(clients[i],
305                                       i % GUC_CLIENT_PRIORITY_NUM, false);
306                 if (err) {
307                         pr_err("[%d] client_alloc sanity check failed!\n", i);
308                         err = -EINVAL;
309                         goto out;
310                 }
311
312                 db_id = clients[i]->doorbell_id;
313
314                 err = create_doorbell(clients[i]);
315                 if (err) {
316                         pr_err("[%d] Failed to create a doorbell\n", i);
317                         goto out;
318                 }
319
320                 /* doorbell id shouldn't change, we are holding the mutex */
321                 if (db_id != clients[i]->doorbell_id) {
322                         pr_err("[%d] doorbell id changed (%d != %d)\n",
323                                i, db_id, clients[i]->doorbell_id);
324                         err = -EINVAL;
325                         goto out;
326                 }
327
328                 err = check_all_doorbells(guc);
329                 if (err)
330                         goto out;
331         }
332
333 out:
334         for (i = 0; i < ATTEMPTS; i++)
335                 if (!IS_ERR_OR_NULL(clients[i])) {
336                         destroy_doorbell(clients[i]);
337                         guc_client_free(clients[i]);
338                 }
339 unlock:
340         mutex_unlock(&dev_priv->drm.struct_mutex);
341         return err;
342 }
343
344 int intel_guc_live_selftest(struct drm_i915_private *dev_priv)
345 {
346         static const struct i915_subtest tests[] = {
347                 SUBTEST(igt_guc_clients),
348                 SUBTEST(igt_guc_doorbells),
349         };
350
351         if (!USES_GUC_SUBMISSION(dev_priv))
352                 return 0;
353
354         return i915_subtests(tests, dev_priv);
355 }
This page took 0.055144 seconds and 4 git commands to generate.