1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2017 Intel Corporation
4  */
5 
6 #include "i915_selftest.h"
7 #include "gem/i915_gem_pm.h"
8 
9 /* max doorbell number + negative test for each client type */
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 	/* first half is used for normal priority, second half for high */
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 	/* if there are no issues GuC will update the WQ head and keep the
67 	 * WQ in active status
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  * Basic client sanity check, handy to validate create_clients.
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  * Check that we're able to synchronize guc_clients with their doorbells
103  *
104  * We're creating clients and reserving doorbells once, at module load. During
105  * module lifetime, GuC, doorbell HW, and i915 state may go out of sync due to
106  * GuC being reset. In other words - GuC clients are still around, but the
107  * status of their doorbells may be incorrect. This is the reason behind
108  * validating that the doorbells status expected by the driver matches what the
109  * GuC/HW have.
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 	wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
120 
121 	guc = &dev_priv->gt.uc.guc;
122 	if (!guc) {
123 		pr_err("No guc object!\n");
124 		err = -EINVAL;
125 		goto unlock;
126 	}
127 
128 	err = check_all_doorbells(guc);
129 	if (err)
130 		goto unlock;
131 
132 	/*
133 	 * Get rid of clients created during driver load because the test will
134 	 * recreate them.
135 	 */
136 	guc_clients_disable(guc);
137 	guc_clients_destroy(guc);
138 	if (guc->execbuf_client) {
139 		pr_err("guc_clients_destroy lied!\n");
140 		err = -EINVAL;
141 		goto unlock;
142 	}
143 
144 	err = guc_clients_create(guc);
145 	if (err) {
146 		pr_err("Failed to create clients\n");
147 		goto unlock;
148 	}
149 	GEM_BUG_ON(!guc->execbuf_client);
150 
151 	err = validate_client(guc->execbuf_client,
152 			      GUC_CLIENT_PRIORITY_KMD_NORMAL);
153 	if (err) {
154 		pr_err("execbug client validation failed\n");
155 		goto out;
156 	}
157 
158 	/* the client should now have reserved a doorbell */
159 	if (!has_doorbell(guc->execbuf_client)) {
160 		pr_err("guc_clients_create didn't reserve doorbells\n");
161 		err = -EINVAL;
162 		goto out;
163 	}
164 
165 	/* Now enable the clients */
166 	guc_clients_enable(guc);
167 
168 	/* each client should now have received a doorbell */
169 	if (!client_doorbell_in_sync(guc->execbuf_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 = create_doorbell(guc->execbuf_client);
180 
181 out:
182 	/*
183 	 * Leave clean state for other test, plus the driver always destroy the
184 	 * clients during unload.
185 	 */
186 	guc_clients_disable(guc);
187 	guc_clients_destroy(guc);
188 	guc_clients_create(guc);
189 	guc_clients_enable(guc);
190 unlock:
191 	intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
192 	return err;
193 }
194 
195 /*
196  * Create as many clients as number of doorbells. Note that there's already
197  * client(s)/doorbell(s) created during driver load, but this test creates
198  * its own and do not interact with the existing ones.
199  */
200 static int igt_guc_doorbells(void *arg)
201 {
202 	struct drm_i915_private *dev_priv = arg;
203 	intel_wakeref_t wakeref;
204 	struct intel_guc *guc;
205 	int i, err = 0;
206 	u16 db_id;
207 
208 	GEM_BUG_ON(!HAS_GT_UC(dev_priv));
209 	wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
210 
211 	guc = &dev_priv->gt.uc.guc;
212 	if (!guc) {
213 		pr_err("No guc object!\n");
214 		err = -EINVAL;
215 		goto unlock;
216 	}
217 
218 	err = check_all_doorbells(guc);
219 	if (err)
220 		goto unlock;
221 
222 	for (i = 0; i < ATTEMPTS; i++) {
223 		clients[i] = guc_client_alloc(guc, i % GUC_CLIENT_PRIORITY_NUM);
224 
225 		if (!clients[i]) {
226 			pr_err("[%d] No guc client\n", i);
227 			err = -EINVAL;
228 			goto out;
229 		}
230 
231 		if (IS_ERR(clients[i])) {
232 			if (PTR_ERR(clients[i]) != -ENOSPC) {
233 				pr_err("[%d] unexpected error\n", i);
234 				err = PTR_ERR(clients[i]);
235 				goto out;
236 			}
237 
238 			if (available_dbs(guc, i % GUC_CLIENT_PRIORITY_NUM)) {
239 				pr_err("[%d] non-db related alloc fail\n", i);
240 				err = -EINVAL;
241 				goto out;
242 			}
243 
244 			/* expected, ran out of dbs for this client type */
245 			continue;
246 		}
247 
248 		/*
249 		 * The check below is only valid because we keep a doorbell
250 		 * assigned during the whole life of the client.
251 		 */
252 		if (clients[i]->stage_id >= GUC_NUM_DOORBELLS) {
253 			pr_err("[%d] more clients than doorbells (%d >= %d)\n",
254 			       i, clients[i]->stage_id, GUC_NUM_DOORBELLS);
255 			err = -EINVAL;
256 			goto out;
257 		}
258 
259 		err = validate_client(clients[i], i % GUC_CLIENT_PRIORITY_NUM);
260 		if (err) {
261 			pr_err("[%d] client_alloc sanity check failed!\n", i);
262 			err = -EINVAL;
263 			goto out;
264 		}
265 
266 		db_id = clients[i]->doorbell_id;
267 
268 		err = __guc_client_enable(clients[i]);
269 		if (err) {
270 			pr_err("[%d] Failed to create a doorbell\n", i);
271 			goto out;
272 		}
273 
274 		/* doorbell id shouldn't change, we are holding the mutex */
275 		if (db_id != clients[i]->doorbell_id) {
276 			pr_err("[%d] doorbell id changed (%d != %d)\n",
277 			       i, db_id, clients[i]->doorbell_id);
278 			err = -EINVAL;
279 			goto out;
280 		}
281 
282 		err = check_all_doorbells(guc);
283 		if (err)
284 			goto out;
285 
286 		err = ring_doorbell_nop(clients[i]);
287 		if (err)
288 			goto out;
289 	}
290 
291 out:
292 	for (i = 0; i < ATTEMPTS; i++)
293 		if (!IS_ERR_OR_NULL(clients[i])) {
294 			__guc_client_disable(clients[i]);
295 			guc_client_free(clients[i]);
296 		}
297 unlock:
298 	intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
299 	return err;
300 }
301 
302 int intel_guc_live_selftest(struct drm_i915_private *dev_priv)
303 {
304 	static const struct i915_subtest tests[] = {
305 		SUBTEST(igt_guc_clients),
306 		SUBTEST(igt_guc_doorbells),
307 	};
308 
309 	if (!USES_GUC_SUBMISSION(dev_priv))
310 		return 0;
311 
312 	return i915_subtests(tests, dev_priv);
313 }
314