Linux-libre 5.3.12-gnu
[librecmc/linux-libre.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 #include "gem/i915_gem_pm.h"
27
28 /* max doorbell number + negative test for each client type */
29 #define ATTEMPTS (GUC_NUM_DOORBELLS + GUC_CLIENT_PRIORITY_NUM)
30
31 static struct intel_guc_client *clients[ATTEMPTS];
32
33 static bool available_dbs(struct intel_guc *guc, u32 priority)
34 {
35         unsigned long offset;
36         unsigned long end;
37         u16 id;
38
39         /* first half is used for normal priority, second half for high */
40         offset = 0;
41         end = GUC_NUM_DOORBELLS / 2;
42         if (priority <= GUC_CLIENT_PRIORITY_HIGH) {
43                 offset = end;
44                 end += offset;
45         }
46
47         id = find_next_zero_bit(guc->doorbell_bitmap, end, offset);
48         if (id < end)
49                 return true;
50
51         return false;
52 }
53
54 static int check_all_doorbells(struct intel_guc *guc)
55 {
56         u16 db_id;
57
58         pr_info_once("Max number of doorbells: %d", GUC_NUM_DOORBELLS);
59         for (db_id = 0; db_id < GUC_NUM_DOORBELLS; ++db_id) {
60                 if (!doorbell_ok(guc, db_id)) {
61                         pr_err("doorbell %d, not ok\n", db_id);
62                         return -EIO;
63                 }
64         }
65
66         return 0;
67 }
68
69 static int ring_doorbell_nop(struct intel_guc_client *client)
70 {
71         struct guc_process_desc *desc = __get_process_desc(client);
72         int err;
73
74         client->use_nop_wqi = true;
75
76         spin_lock_irq(&client->wq_lock);
77
78         guc_wq_item_append(client, 0, 0, 0, 0);
79         guc_ring_doorbell(client);
80
81         spin_unlock_irq(&client->wq_lock);
82
83         client->use_nop_wqi = false;
84
85         /* if there are no issues GuC will update the WQ head and keep the
86          * WQ in active status
87          */
88         err = wait_for(READ_ONCE(desc->head) == READ_ONCE(desc->tail), 10);
89         if (err) {
90                 pr_err("doorbell %u ring failed!\n", client->doorbell_id);
91                 return -EIO;
92         }
93
94         if (desc->wq_status != WQ_STATUS_ACTIVE) {
95                 pr_err("doorbell %u ring put WQ in bad state (%u)!\n",
96                        client->doorbell_id, desc->wq_status);
97                 return -EIO;
98         }
99
100         return 0;
101 }
102
103 /*
104  * Basic client sanity check, handy to validate create_clients.
105  */
106 static int validate_client(struct intel_guc_client *client,
107                            int client_priority,
108                            bool is_preempt_client)
109 {
110         struct drm_i915_private *dev_priv = guc_to_i915(client->guc);
111         struct i915_gem_context *ctx_owner = is_preempt_client ?
112                         dev_priv->preempt_context : dev_priv->kernel_context;
113
114         if (client->owner != ctx_owner ||
115             client->engines != INTEL_INFO(dev_priv)->engine_mask ||
116             client->priority != client_priority ||
117             client->doorbell_id == GUC_DOORBELL_INVALID)
118                 return -EINVAL;
119         else
120                 return 0;
121 }
122
123 static bool client_doorbell_in_sync(struct intel_guc_client *client)
124 {
125         return !client || doorbell_ok(client->guc, client->doorbell_id);
126 }
127
128 /*
129  * Check that we're able to synchronize guc_clients with their doorbells
130  *
131  * We're creating clients and reserving doorbells once, at module load. During
132  * module lifetime, GuC, doorbell HW, and i915 state may go out of sync due to
133  * GuC being reset. In other words - GuC clients are still around, but the
134  * status of their doorbells may be incorrect. This is the reason behind
135  * validating that the doorbells status expected by the driver matches what the
136  * GuC/HW have.
137  */
138 static int igt_guc_clients(void *args)
139 {
140         struct drm_i915_private *dev_priv = args;
141         intel_wakeref_t wakeref;
142         struct intel_guc *guc;
143         int err = 0;
144
145         GEM_BUG_ON(!HAS_GUC(dev_priv));
146         mutex_lock(&dev_priv->drm.struct_mutex);
147         wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
148
149         guc = &dev_priv->guc;
150         if (!guc) {
151                 pr_err("No guc object!\n");
152                 err = -EINVAL;
153                 goto unlock;
154         }
155
156         err = check_all_doorbells(guc);
157         if (err)
158                 goto unlock;
159
160         /*
161          * Get rid of clients created during driver load because the test will
162          * recreate them.
163          */
164         guc_clients_disable(guc);
165         guc_clients_destroy(guc);
166         if (guc->execbuf_client || guc->preempt_client) {
167                 pr_err("guc_clients_destroy lied!\n");
168                 err = -EINVAL;
169                 goto unlock;
170         }
171
172         err = guc_clients_create(guc);
173         if (err) {
174                 pr_err("Failed to create clients\n");
175                 goto unlock;
176         }
177         GEM_BUG_ON(!guc->execbuf_client);
178
179         err = validate_client(guc->execbuf_client,
180                               GUC_CLIENT_PRIORITY_KMD_NORMAL, false);
181         if (err) {
182                 pr_err("execbug client validation failed\n");
183                 goto out;
184         }
185
186         if (guc->preempt_client) {
187                 err = validate_client(guc->preempt_client,
188                                       GUC_CLIENT_PRIORITY_KMD_HIGH, true);
189                 if (err) {
190                         pr_err("preempt client validation failed\n");
191                         goto out;
192                 }
193         }
194
195         /* each client should now have reserved a doorbell */
196         if (!has_doorbell(guc->execbuf_client) ||
197             (guc->preempt_client && !has_doorbell(guc->preempt_client))) {
198                 pr_err("guc_clients_create didn't reserve doorbells\n");
199                 err = -EINVAL;
200                 goto out;
201         }
202
203         /* Now enable the clients */
204         guc_clients_enable(guc);
205
206         /* each client should now have received a doorbell */
207         if (!client_doorbell_in_sync(guc->execbuf_client) ||
208             !client_doorbell_in_sync(guc->preempt_client)) {
209                 pr_err("failed to initialize the doorbells\n");
210                 err = -EINVAL;
211                 goto out;
212         }
213
214         /*
215          * Basic test - an attempt to reallocate a valid doorbell to the
216          * client it is currently assigned should not cause a failure.
217          */
218         err = create_doorbell(guc->execbuf_client);
219
220 out:
221         /*
222          * Leave clean state for other test, plus the driver always destroy the
223          * clients during unload.
224          */
225         guc_clients_disable(guc);
226         guc_clients_destroy(guc);
227         guc_clients_create(guc);
228         guc_clients_enable(guc);
229 unlock:
230         intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
231         mutex_unlock(&dev_priv->drm.struct_mutex);
232         return err;
233 }
234
235 /*
236  * Create as many clients as number of doorbells. Note that there's already
237  * client(s)/doorbell(s) created during driver load, but this test creates
238  * its own and do not interact with the existing ones.
239  */
240 static int igt_guc_doorbells(void *arg)
241 {
242         struct drm_i915_private *dev_priv = arg;
243         intel_wakeref_t wakeref;
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         wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
251
252         guc = &dev_priv->guc;
253         if (!guc) {
254                 pr_err("No guc object!\n");
255                 err = -EINVAL;
256                 goto unlock;
257         }
258
259         err = check_all_doorbells(guc);
260         if (err)
261                 goto unlock;
262
263         for (i = 0; i < ATTEMPTS; i++) {
264                 clients[i] = guc_client_alloc(dev_priv,
265                                               INTEL_INFO(dev_priv)->engine_mask,
266                                               i % GUC_CLIENT_PRIORITY_NUM,
267                                               dev_priv->kernel_context);
268
269                 if (!clients[i]) {
270                         pr_err("[%d] No guc client\n", i);
271                         err = -EINVAL;
272                         goto out;
273                 }
274
275                 if (IS_ERR(clients[i])) {
276                         if (PTR_ERR(clients[i]) != -ENOSPC) {
277                                 pr_err("[%d] unexpected error\n", i);
278                                 err = PTR_ERR(clients[i]);
279                                 goto out;
280                         }
281
282                         if (available_dbs(guc, i % GUC_CLIENT_PRIORITY_NUM)) {
283                                 pr_err("[%d] non-db related alloc fail\n", i);
284                                 err = -EINVAL;
285                                 goto out;
286                         }
287
288                         /* expected, ran out of dbs for this client type */
289                         continue;
290                 }
291
292                 /*
293                  * The check below is only valid because we keep a doorbell
294                  * assigned during the whole life of the client.
295                  */
296                 if (clients[i]->stage_id >= GUC_NUM_DOORBELLS) {
297                         pr_err("[%d] more clients than doorbells (%d >= %d)\n",
298                                i, clients[i]->stage_id, GUC_NUM_DOORBELLS);
299                         err = -EINVAL;
300                         goto out;
301                 }
302
303                 err = validate_client(clients[i],
304                                       i % GUC_CLIENT_PRIORITY_NUM, false);
305                 if (err) {
306                         pr_err("[%d] client_alloc sanity check failed!\n", i);
307                         err = -EINVAL;
308                         goto out;
309                 }
310
311                 db_id = clients[i]->doorbell_id;
312
313                 err = __guc_client_enable(clients[i]);
314                 if (err) {
315                         pr_err("[%d] Failed to create a doorbell\n", i);
316                         goto out;
317                 }
318
319                 /* doorbell id shouldn't change, we are holding the mutex */
320                 if (db_id != clients[i]->doorbell_id) {
321                         pr_err("[%d] doorbell id changed (%d != %d)\n",
322                                i, db_id, clients[i]->doorbell_id);
323                         err = -EINVAL;
324                         goto out;
325                 }
326
327                 err = check_all_doorbells(guc);
328                 if (err)
329                         goto out;
330
331                 err = ring_doorbell_nop(clients[i]);
332                 if (err)
333                         goto out;
334         }
335
336 out:
337         for (i = 0; i < ATTEMPTS; i++)
338                 if (!IS_ERR_OR_NULL(clients[i])) {
339                         __guc_client_disable(clients[i]);
340                         guc_client_free(clients[i]);
341                 }
342 unlock:
343         intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
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 }