3f9016466deaf74ebfb64587a5f6006a5202c249
[linux-2.6-block.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 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         GEM_BUG_ON(!guc->preempt_client);
141
142         err = validate_client(guc->execbuf_client,
143                               GUC_CLIENT_PRIORITY_KMD_NORMAL, false);
144         if (err) {
145                 pr_err("execbug client validation failed\n");
146                 goto out;
147         }
148
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         /* each client should now have reserved a doorbell */
157         if (!has_doorbell(guc->execbuf_client) ||
158             !has_doorbell(guc->preempt_client)) {
159                 pr_err("guc_clients_create didn't reserve doorbells\n");
160                 err = -EINVAL;
161                 goto out;
162         }
163
164         /* Now create the doorbells */
165         guc_clients_doorbell_init(guc);
166
167         /* each client should now have received a doorbell */
168         if (!client_doorbell_in_sync(guc->execbuf_client) ||
169             !client_doorbell_in_sync(guc->preempt_client)) {
170                 pr_err("failed to initialize the doorbells\n");
171                 err = -EINVAL;
172                 goto out;
173         }
174
175         /*
176          * Basic test - an attempt to reallocate a valid doorbell to the
177          * client it is currently assigned should not cause a failure.
178          */
179         err = guc_clients_doorbell_init(guc);
180         if (err)
181                 goto out;
182
183         /*
184          * Negative test - a client with no doorbell (invalid db id).
185          * After destroying the doorbell, the db id is changed to
186          * GUC_DOORBELL_INVALID and the firmware will reject any attempt to
187          * allocate a doorbell with an invalid id (db has to be reserved before
188          * allocation).
189          */
190         destroy_doorbell(guc->execbuf_client);
191         if (client_doorbell_in_sync(guc->execbuf_client)) {
192                 pr_err("destroy db did not work\n");
193                 err = -EINVAL;
194                 goto out;
195         }
196
197         unreserve_doorbell(guc->execbuf_client);
198         err = guc_clients_doorbell_init(guc);
199         if (err != -EIO) {
200                 pr_err("unexpected (err = %d)", err);
201                 goto out;
202         }
203
204         if (!available_dbs(guc, guc->execbuf_client->priority)) {
205                 pr_err("doorbell not available when it should\n");
206                 err = -EIO;
207                 goto out;
208         }
209
210         /* clean after test */
211         err = reserve_doorbell(guc->execbuf_client);
212         if (err) {
213                 pr_err("failed to reserve back the doorbell back\n");
214         }
215         err = create_doorbell(guc->execbuf_client);
216         if (err) {
217                 pr_err("recreate doorbell failed\n");
218                 goto out;
219         }
220
221 out:
222         /*
223          * Leave clean state for other test, plus the driver always destroy the
224          * clients during unload.
225          */
226         destroy_doorbell(guc->execbuf_client);
227         destroy_doorbell(guc->preempt_client);
228         guc_clients_destroy(guc);
229         guc_clients_create(guc);
230         guc_clients_doorbell_init(guc);
231 unlock:
232         mutex_unlock(&dev_priv->drm.struct_mutex);
233         return err;
234 }
235
236 /*
237  * Create as many clients as number of doorbells. Note that there's already
238  * client(s)/doorbell(s) created during driver load, but this test creates
239  * its own and do not interact with the existing ones.
240  */
241 static int igt_guc_doorbells(void *arg)
242 {
243         struct drm_i915_private *dev_priv = arg;
244         struct intel_guc *guc;
245         int i, err = 0;
246         u16 db_id;
247
248         GEM_BUG_ON(!HAS_GUC(dev_priv));
249         mutex_lock(&dev_priv->drm.struct_mutex);
250
251         guc = &dev_priv->guc;
252         if (!guc) {
253                 pr_err("No guc object!\n");
254                 err = -EINVAL;
255                 goto unlock;
256         }
257
258         err = check_all_doorbells(guc);
259         if (err)
260                 goto unlock;
261
262         for (i = 0; i < ATTEMPTS; i++) {
263                 clients[i] = guc_client_alloc(dev_priv,
264                                               INTEL_INFO(dev_priv)->ring_mask,
265                                               i % GUC_CLIENT_PRIORITY_NUM,
266                                               dev_priv->kernel_context);
267
268                 if (!clients[i]) {
269                         pr_err("[%d] No guc client\n", i);
270                         err = -EINVAL;
271                         goto out;
272                 }
273
274                 if (IS_ERR(clients[i])) {
275                         if (PTR_ERR(clients[i]) != -ENOSPC) {
276                                 pr_err("[%d] unexpected error\n", i);
277                                 err = PTR_ERR(clients[i]);
278                                 goto out;
279                         }
280
281                         if (available_dbs(guc, i % GUC_CLIENT_PRIORITY_NUM)) {
282                                 pr_err("[%d] non-db related alloc fail\n", i);
283                                 err = -EINVAL;
284                                 goto out;
285                         }
286
287                         /* expected, ran out of dbs for this client type */
288                         continue;
289                 }
290
291                 /*
292                  * The check below is only valid because we keep a doorbell
293                  * assigned during the whole life of the client.
294                  */
295                 if (clients[i]->stage_id >= GUC_NUM_DOORBELLS) {
296                         pr_err("[%d] more clients than doorbells (%d >= %d)\n",
297                                i, clients[i]->stage_id, GUC_NUM_DOORBELLS);
298                         err = -EINVAL;
299                         goto out;
300                 }
301
302                 err = validate_client(clients[i],
303                                       i % GUC_CLIENT_PRIORITY_NUM, false);
304                 if (err) {
305                         pr_err("[%d] client_alloc sanity check failed!\n", i);
306                         err = -EINVAL;
307                         goto out;
308                 }
309
310                 db_id = clients[i]->doorbell_id;
311
312                 err = create_doorbell(clients[i]);
313                 if (err) {
314                         pr_err("[%d] Failed to create a doorbell\n", i);
315                         goto out;
316                 }
317
318                 /* doorbell id shouldn't change, we are holding the mutex */
319                 if (db_id != clients[i]->doorbell_id) {
320                         pr_err("[%d] doorbell id changed (%d != %d)\n",
321                                i, db_id, clients[i]->doorbell_id);
322                         err = -EINVAL;
323                         goto out;
324                 }
325
326                 err = check_all_doorbells(guc);
327                 if (err)
328                         goto out;
329         }
330
331 out:
332         for (i = 0; i < ATTEMPTS; i++)
333                 if (!IS_ERR_OR_NULL(clients[i])) {
334                         destroy_doorbell(clients[i]);
335                         guc_client_free(clients[i]);
336                 }
337 unlock:
338         mutex_unlock(&dev_priv->drm.struct_mutex);
339         return err;
340 }
341
342 int intel_guc_live_selftest(struct drm_i915_private *dev_priv)
343 {
344         static const struct i915_subtest tests[] = {
345                 SUBTEST(igt_guc_clients),
346                 SUBTEST(igt_guc_doorbells),
347         };
348
349         if (!USES_GUC_SUBMISSION(dev_priv))
350                 return 0;
351
352         return i915_subtests(tests, dev_priv);
353 }