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, int client_priority) 107 { 108 if (client->priority != client_priority || 109 client->doorbell_id == GUC_DOORBELL_INVALID) 110 return -EINVAL; 111 else 112 return 0; 113 } 114 115 static bool client_doorbell_in_sync(struct intel_guc_client *client) 116 { 117 return !client || doorbell_ok(client->guc, client->doorbell_id); 118 } 119 120 /* 121 * Check that we're able to synchronize guc_clients with their doorbells 122 * 123 * We're creating clients and reserving doorbells once, at module load. During 124 * module lifetime, GuC, doorbell HW, and i915 state may go out of sync due to 125 * GuC being reset. In other words - GuC clients are still around, but the 126 * status of their doorbells may be incorrect. This is the reason behind 127 * validating that the doorbells status expected by the driver matches what the 128 * GuC/HW have. 129 */ 130 static int igt_guc_clients(void *args) 131 { 132 struct drm_i915_private *dev_priv = args; 133 intel_wakeref_t wakeref; 134 struct intel_guc *guc; 135 int err = 0; 136 137 GEM_BUG_ON(!HAS_GT_UC(dev_priv)); 138 mutex_lock(&dev_priv->drm.struct_mutex); 139 wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); 140 141 guc = &dev_priv->gt.uc.guc; 142 if (!guc) { 143 pr_err("No guc object!\n"); 144 err = -EINVAL; 145 goto unlock; 146 } 147 148 err = check_all_doorbells(guc); 149 if (err) 150 goto unlock; 151 152 /* 153 * Get rid of clients created during driver load because the test will 154 * recreate them. 155 */ 156 guc_clients_disable(guc); 157 guc_clients_destroy(guc); 158 if (guc->execbuf_client) { 159 pr_err("guc_clients_destroy lied!\n"); 160 err = -EINVAL; 161 goto unlock; 162 } 163 164 err = guc_clients_create(guc); 165 if (err) { 166 pr_err("Failed to create clients\n"); 167 goto unlock; 168 } 169 GEM_BUG_ON(!guc->execbuf_client); 170 171 err = validate_client(guc->execbuf_client, 172 GUC_CLIENT_PRIORITY_KMD_NORMAL); 173 if (err) { 174 pr_err("execbug client validation failed\n"); 175 goto out; 176 } 177 178 /* the client should now have reserved a doorbell */ 179 if (!has_doorbell(guc->execbuf_client)) { 180 pr_err("guc_clients_create didn't reserve doorbells\n"); 181 err = -EINVAL; 182 goto out; 183 } 184 185 /* Now enable the clients */ 186 guc_clients_enable(guc); 187 188 /* each client should now have received a doorbell */ 189 if (!client_doorbell_in_sync(guc->execbuf_client)) { 190 pr_err("failed to initialize the doorbells\n"); 191 err = -EINVAL; 192 goto out; 193 } 194 195 /* 196 * Basic test - an attempt to reallocate a valid doorbell to the 197 * client it is currently assigned should not cause a failure. 198 */ 199 err = create_doorbell(guc->execbuf_client); 200 201 out: 202 /* 203 * Leave clean state for other test, plus the driver always destroy the 204 * clients during unload. 205 */ 206 guc_clients_disable(guc); 207 guc_clients_destroy(guc); 208 guc_clients_create(guc); 209 guc_clients_enable(guc); 210 unlock: 211 intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); 212 mutex_unlock(&dev_priv->drm.struct_mutex); 213 return err; 214 } 215 216 /* 217 * Create as many clients as number of doorbells. Note that there's already 218 * client(s)/doorbell(s) created during driver load, but this test creates 219 * its own and do not interact with the existing ones. 220 */ 221 static int igt_guc_doorbells(void *arg) 222 { 223 struct drm_i915_private *dev_priv = arg; 224 intel_wakeref_t wakeref; 225 struct intel_guc *guc; 226 int i, err = 0; 227 u16 db_id; 228 229 GEM_BUG_ON(!HAS_GT_UC(dev_priv)); 230 mutex_lock(&dev_priv->drm.struct_mutex); 231 wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); 232 233 guc = &dev_priv->gt.uc.guc; 234 if (!guc) { 235 pr_err("No guc object!\n"); 236 err = -EINVAL; 237 goto unlock; 238 } 239 240 err = check_all_doorbells(guc); 241 if (err) 242 goto unlock; 243 244 for (i = 0; i < ATTEMPTS; i++) { 245 clients[i] = guc_client_alloc(guc, i % GUC_CLIENT_PRIORITY_NUM); 246 247 if (!clients[i]) { 248 pr_err("[%d] No guc client\n", i); 249 err = -EINVAL; 250 goto out; 251 } 252 253 if (IS_ERR(clients[i])) { 254 if (PTR_ERR(clients[i]) != -ENOSPC) { 255 pr_err("[%d] unexpected error\n", i); 256 err = PTR_ERR(clients[i]); 257 goto out; 258 } 259 260 if (available_dbs(guc, i % GUC_CLIENT_PRIORITY_NUM)) { 261 pr_err("[%d] non-db related alloc fail\n", i); 262 err = -EINVAL; 263 goto out; 264 } 265 266 /* expected, ran out of dbs for this client type */ 267 continue; 268 } 269 270 /* 271 * The check below is only valid because we keep a doorbell 272 * assigned during the whole life of the client. 273 */ 274 if (clients[i]->stage_id >= GUC_NUM_DOORBELLS) { 275 pr_err("[%d] more clients than doorbells (%d >= %d)\n", 276 i, clients[i]->stage_id, GUC_NUM_DOORBELLS); 277 err = -EINVAL; 278 goto out; 279 } 280 281 err = validate_client(clients[i], i % GUC_CLIENT_PRIORITY_NUM); 282 if (err) { 283 pr_err("[%d] client_alloc sanity check failed!\n", i); 284 err = -EINVAL; 285 goto out; 286 } 287 288 db_id = clients[i]->doorbell_id; 289 290 err = __guc_client_enable(clients[i]); 291 if (err) { 292 pr_err("[%d] Failed to create a doorbell\n", i); 293 goto out; 294 } 295 296 /* doorbell id shouldn't change, we are holding the mutex */ 297 if (db_id != clients[i]->doorbell_id) { 298 pr_err("[%d] doorbell id changed (%d != %d)\n", 299 i, db_id, clients[i]->doorbell_id); 300 err = -EINVAL; 301 goto out; 302 } 303 304 err = check_all_doorbells(guc); 305 if (err) 306 goto out; 307 308 err = ring_doorbell_nop(clients[i]); 309 if (err) 310 goto out; 311 } 312 313 out: 314 for (i = 0; i < ATTEMPTS; i++) 315 if (!IS_ERR_OR_NULL(clients[i])) { 316 __guc_client_disable(clients[i]); 317 guc_client_free(clients[i]); 318 } 319 unlock: 320 intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); 321 mutex_unlock(&dev_priv->drm.struct_mutex); 322 return err; 323 } 324 325 int intel_guc_live_selftest(struct drm_i915_private *dev_priv) 326 { 327 static const struct i915_subtest tests[] = { 328 SUBTEST(igt_guc_clients), 329 SUBTEST(igt_guc_doorbells), 330 }; 331 332 if (!USES_GUC_SUBMISSION(dev_priv)) 333 return 0; 334 335 return i915_subtests(tests, dev_priv); 336 } 337