1112ed2d3SChris Wilson /* 2112ed2d3SChris Wilson * SPDX-License-Identifier: MIT 3112ed2d3SChris Wilson * 4112ed2d3SChris Wilson * Copyright © 2018 Intel Corporation 5112ed2d3SChris Wilson */ 6112ed2d3SChris Wilson 710be98a7SChris Wilson #include "gem/i915_gem_pm.h" 8112ed2d3SChris Wilson #include "i915_selftest.h" 9112ed2d3SChris Wilson #include "intel_reset.h" 10112ed2d3SChris Wilson 11112ed2d3SChris Wilson #include "selftests/igt_flush_test.h" 12112ed2d3SChris Wilson #include "selftests/igt_reset.h" 13112ed2d3SChris Wilson #include "selftests/igt_spinner.h" 14112ed2d3SChris Wilson #include "selftests/igt_wedge_me.h" 15112ed2d3SChris Wilson #include "selftests/mock_drm.h" 16112ed2d3SChris Wilson 1710be98a7SChris Wilson #include "gem/selftests/igt_gem_utils.h" 1810be98a7SChris Wilson #include "gem/selftests/mock_context.h" 1910be98a7SChris Wilson 20112ed2d3SChris Wilson static const struct wo_register { 21112ed2d3SChris Wilson enum intel_platform platform; 22112ed2d3SChris Wilson u32 reg; 23112ed2d3SChris Wilson } wo_registers[] = { 24112ed2d3SChris Wilson { INTEL_GEMINILAKE, 0x731c } 25112ed2d3SChris Wilson }; 26112ed2d3SChris Wilson 27fde93886STvrtko Ursulin #define REF_NAME_MAX (INTEL_ENGINE_CS_MAX_NAME + 8) 28112ed2d3SChris Wilson struct wa_lists { 29112ed2d3SChris Wilson struct i915_wa_list gt_wa_list; 30112ed2d3SChris Wilson struct { 31112ed2d3SChris Wilson char name[REF_NAME_MAX]; 32112ed2d3SChris Wilson struct i915_wa_list wa_list; 33fde93886STvrtko Ursulin struct i915_wa_list ctx_wa_list; 34112ed2d3SChris Wilson } engine[I915_NUM_ENGINES]; 35112ed2d3SChris Wilson }; 36112ed2d3SChris Wilson 37112ed2d3SChris Wilson static void 38112ed2d3SChris Wilson reference_lists_init(struct drm_i915_private *i915, struct wa_lists *lists) 39112ed2d3SChris Wilson { 40112ed2d3SChris Wilson struct intel_engine_cs *engine; 41112ed2d3SChris Wilson enum intel_engine_id id; 42112ed2d3SChris Wilson 43112ed2d3SChris Wilson memset(lists, 0, sizeof(*lists)); 44112ed2d3SChris Wilson 45112ed2d3SChris Wilson wa_init_start(&lists->gt_wa_list, "GT_REF"); 46112ed2d3SChris Wilson gt_init_workarounds(i915, &lists->gt_wa_list); 47112ed2d3SChris Wilson wa_init_finish(&lists->gt_wa_list); 48112ed2d3SChris Wilson 49112ed2d3SChris Wilson for_each_engine(engine, i915, id) { 50112ed2d3SChris Wilson struct i915_wa_list *wal = &lists->engine[id].wa_list; 51112ed2d3SChris Wilson char *name = lists->engine[id].name; 52112ed2d3SChris Wilson 53112ed2d3SChris Wilson snprintf(name, REF_NAME_MAX, "%s_REF", engine->name); 54112ed2d3SChris Wilson 55112ed2d3SChris Wilson wa_init_start(wal, name); 56112ed2d3SChris Wilson engine_init_workarounds(engine, wal); 57112ed2d3SChris Wilson wa_init_finish(wal); 58fde93886STvrtko Ursulin 59fde93886STvrtko Ursulin snprintf(name, REF_NAME_MAX, "%s_CTX_REF", engine->name); 60fde93886STvrtko Ursulin 61fde93886STvrtko Ursulin __intel_engine_init_ctx_wa(engine, 62fde93886STvrtko Ursulin &lists->engine[id].ctx_wa_list, 63fde93886STvrtko Ursulin name); 64112ed2d3SChris Wilson } 65112ed2d3SChris Wilson } 66112ed2d3SChris Wilson 67112ed2d3SChris Wilson static void 68112ed2d3SChris Wilson reference_lists_fini(struct drm_i915_private *i915, struct wa_lists *lists) 69112ed2d3SChris Wilson { 70112ed2d3SChris Wilson struct intel_engine_cs *engine; 71112ed2d3SChris Wilson enum intel_engine_id id; 72112ed2d3SChris Wilson 73112ed2d3SChris Wilson for_each_engine(engine, i915, id) 74112ed2d3SChris Wilson intel_wa_list_free(&lists->engine[id].wa_list); 75112ed2d3SChris Wilson 76112ed2d3SChris Wilson intel_wa_list_free(&lists->gt_wa_list); 77112ed2d3SChris Wilson } 78112ed2d3SChris Wilson 79112ed2d3SChris Wilson static struct drm_i915_gem_object * 80112ed2d3SChris Wilson read_nonprivs(struct i915_gem_context *ctx, struct intel_engine_cs *engine) 81112ed2d3SChris Wilson { 82112ed2d3SChris Wilson const u32 base = engine->mmio_base; 83112ed2d3SChris Wilson struct drm_i915_gem_object *result; 84112ed2d3SChris Wilson struct i915_request *rq; 85112ed2d3SChris Wilson struct i915_vma *vma; 86112ed2d3SChris Wilson u32 srm, *cs; 87112ed2d3SChris Wilson int err; 88112ed2d3SChris Wilson int i; 89112ed2d3SChris Wilson 90112ed2d3SChris Wilson result = i915_gem_object_create_internal(engine->i915, PAGE_SIZE); 91112ed2d3SChris Wilson if (IS_ERR(result)) 92112ed2d3SChris Wilson return result; 93112ed2d3SChris Wilson 94112ed2d3SChris Wilson i915_gem_object_set_cache_coherency(result, I915_CACHE_LLC); 95112ed2d3SChris Wilson 96112ed2d3SChris Wilson cs = i915_gem_object_pin_map(result, I915_MAP_WB); 97112ed2d3SChris Wilson if (IS_ERR(cs)) { 98112ed2d3SChris Wilson err = PTR_ERR(cs); 99112ed2d3SChris Wilson goto err_obj; 100112ed2d3SChris Wilson } 101112ed2d3SChris Wilson memset(cs, 0xc5, PAGE_SIZE); 102112ed2d3SChris Wilson i915_gem_object_flush_map(result); 103112ed2d3SChris Wilson i915_gem_object_unpin_map(result); 104112ed2d3SChris Wilson 105112ed2d3SChris Wilson vma = i915_vma_instance(result, &engine->i915->ggtt.vm, NULL); 106112ed2d3SChris Wilson if (IS_ERR(vma)) { 107112ed2d3SChris Wilson err = PTR_ERR(vma); 108112ed2d3SChris Wilson goto err_obj; 109112ed2d3SChris Wilson } 110112ed2d3SChris Wilson 111112ed2d3SChris Wilson err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL); 112112ed2d3SChris Wilson if (err) 113112ed2d3SChris Wilson goto err_obj; 114112ed2d3SChris Wilson 11546472b3eSChris Wilson rq = igt_request_alloc(ctx, engine); 116112ed2d3SChris Wilson if (IS_ERR(rq)) { 117112ed2d3SChris Wilson err = PTR_ERR(rq); 118112ed2d3SChris Wilson goto err_pin; 119112ed2d3SChris Wilson } 120112ed2d3SChris Wilson 1216951e589SChris Wilson i915_vma_lock(vma); 122112ed2d3SChris Wilson err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); 1236951e589SChris Wilson i915_vma_unlock(vma); 124112ed2d3SChris Wilson if (err) 125112ed2d3SChris Wilson goto err_req; 126112ed2d3SChris Wilson 127112ed2d3SChris Wilson srm = MI_STORE_REGISTER_MEM | MI_SRM_LRM_GLOBAL_GTT; 128112ed2d3SChris Wilson if (INTEL_GEN(ctx->i915) >= 8) 129112ed2d3SChris Wilson srm++; 130112ed2d3SChris Wilson 131112ed2d3SChris Wilson cs = intel_ring_begin(rq, 4 * RING_MAX_NONPRIV_SLOTS); 132112ed2d3SChris Wilson if (IS_ERR(cs)) { 133112ed2d3SChris Wilson err = PTR_ERR(cs); 134112ed2d3SChris Wilson goto err_req; 135112ed2d3SChris Wilson } 136112ed2d3SChris Wilson 137112ed2d3SChris Wilson for (i = 0; i < RING_MAX_NONPRIV_SLOTS; i++) { 138112ed2d3SChris Wilson *cs++ = srm; 139112ed2d3SChris Wilson *cs++ = i915_mmio_reg_offset(RING_FORCE_TO_NONPRIV(base, i)); 140112ed2d3SChris Wilson *cs++ = i915_ggtt_offset(vma) + sizeof(u32) * i; 141112ed2d3SChris Wilson *cs++ = 0; 142112ed2d3SChris Wilson } 143112ed2d3SChris Wilson intel_ring_advance(rq, cs); 144112ed2d3SChris Wilson 145112ed2d3SChris Wilson i915_request_add(rq); 146112ed2d3SChris Wilson i915_vma_unpin(vma); 147112ed2d3SChris Wilson 148112ed2d3SChris Wilson return result; 149112ed2d3SChris Wilson 150112ed2d3SChris Wilson err_req: 151112ed2d3SChris Wilson i915_request_add(rq); 152112ed2d3SChris Wilson err_pin: 153112ed2d3SChris Wilson i915_vma_unpin(vma); 154112ed2d3SChris Wilson err_obj: 155112ed2d3SChris Wilson i915_gem_object_put(result); 156112ed2d3SChris Wilson return ERR_PTR(err); 157112ed2d3SChris Wilson } 158112ed2d3SChris Wilson 159112ed2d3SChris Wilson static u32 160112ed2d3SChris Wilson get_whitelist_reg(const struct intel_engine_cs *engine, unsigned int i) 161112ed2d3SChris Wilson { 162112ed2d3SChris Wilson i915_reg_t reg = i < engine->whitelist.count ? 163112ed2d3SChris Wilson engine->whitelist.list[i].reg : 164112ed2d3SChris Wilson RING_NOPID(engine->mmio_base); 165112ed2d3SChris Wilson 166112ed2d3SChris Wilson return i915_mmio_reg_offset(reg); 167112ed2d3SChris Wilson } 168112ed2d3SChris Wilson 169112ed2d3SChris Wilson static void 170112ed2d3SChris Wilson print_results(const struct intel_engine_cs *engine, const u32 *results) 171112ed2d3SChris Wilson { 172112ed2d3SChris Wilson unsigned int i; 173112ed2d3SChris Wilson 174112ed2d3SChris Wilson for (i = 0; i < RING_MAX_NONPRIV_SLOTS; i++) { 175112ed2d3SChris Wilson u32 expected = get_whitelist_reg(engine, i); 176112ed2d3SChris Wilson u32 actual = results[i]; 177112ed2d3SChris Wilson 178112ed2d3SChris Wilson pr_info("RING_NONPRIV[%d]: expected 0x%08x, found 0x%08x\n", 179112ed2d3SChris Wilson i, expected, actual); 180112ed2d3SChris Wilson } 181112ed2d3SChris Wilson } 182112ed2d3SChris Wilson 183112ed2d3SChris Wilson static int check_whitelist(struct i915_gem_context *ctx, 184112ed2d3SChris Wilson struct intel_engine_cs *engine) 185112ed2d3SChris Wilson { 186112ed2d3SChris Wilson struct drm_i915_gem_object *results; 187112ed2d3SChris Wilson struct igt_wedge_me wedge; 188112ed2d3SChris Wilson u32 *vaddr; 189112ed2d3SChris Wilson int err; 190112ed2d3SChris Wilson int i; 191112ed2d3SChris Wilson 192112ed2d3SChris Wilson results = read_nonprivs(ctx, engine); 193112ed2d3SChris Wilson if (IS_ERR(results)) 194112ed2d3SChris Wilson return PTR_ERR(results); 195112ed2d3SChris Wilson 196112ed2d3SChris Wilson err = 0; 1976951e589SChris Wilson i915_gem_object_lock(results); 198112ed2d3SChris Wilson igt_wedge_on_timeout(&wedge, ctx->i915, HZ / 5) /* a safety net! */ 199112ed2d3SChris Wilson err = i915_gem_object_set_to_cpu_domain(results, false); 2006951e589SChris Wilson i915_gem_object_unlock(results); 201112ed2d3SChris Wilson if (i915_terminally_wedged(ctx->i915)) 202112ed2d3SChris Wilson err = -EIO; 203112ed2d3SChris Wilson if (err) 204112ed2d3SChris Wilson goto out_put; 205112ed2d3SChris Wilson 206112ed2d3SChris Wilson vaddr = i915_gem_object_pin_map(results, I915_MAP_WB); 207112ed2d3SChris Wilson if (IS_ERR(vaddr)) { 208112ed2d3SChris Wilson err = PTR_ERR(vaddr); 209112ed2d3SChris Wilson goto out_put; 210112ed2d3SChris Wilson } 211112ed2d3SChris Wilson 212112ed2d3SChris Wilson for (i = 0; i < RING_MAX_NONPRIV_SLOTS; i++) { 213112ed2d3SChris Wilson u32 expected = get_whitelist_reg(engine, i); 214112ed2d3SChris Wilson u32 actual = vaddr[i]; 215112ed2d3SChris Wilson 216112ed2d3SChris Wilson if (expected != actual) { 217112ed2d3SChris Wilson print_results(engine, vaddr); 218112ed2d3SChris Wilson pr_err("Invalid RING_NONPRIV[%d], expected 0x%08x, found 0x%08x\n", 219112ed2d3SChris Wilson i, expected, actual); 220112ed2d3SChris Wilson 221112ed2d3SChris Wilson err = -EINVAL; 222112ed2d3SChris Wilson break; 223112ed2d3SChris Wilson } 224112ed2d3SChris Wilson } 225112ed2d3SChris Wilson 226112ed2d3SChris Wilson i915_gem_object_unpin_map(results); 227112ed2d3SChris Wilson out_put: 228112ed2d3SChris Wilson i915_gem_object_put(results); 229112ed2d3SChris Wilson return err; 230112ed2d3SChris Wilson } 231112ed2d3SChris Wilson 232112ed2d3SChris Wilson static int do_device_reset(struct intel_engine_cs *engine) 233112ed2d3SChris Wilson { 234112ed2d3SChris Wilson i915_reset(engine->i915, engine->mask, "live_workarounds"); 235112ed2d3SChris Wilson return 0; 236112ed2d3SChris Wilson } 237112ed2d3SChris Wilson 238112ed2d3SChris Wilson static int do_engine_reset(struct intel_engine_cs *engine) 239112ed2d3SChris Wilson { 240112ed2d3SChris Wilson return i915_reset_engine(engine, "live_workarounds"); 241112ed2d3SChris Wilson } 242112ed2d3SChris Wilson 243112ed2d3SChris Wilson static int 244112ed2d3SChris Wilson switch_to_scratch_context(struct intel_engine_cs *engine, 245112ed2d3SChris Wilson struct igt_spinner *spin) 246112ed2d3SChris Wilson { 247112ed2d3SChris Wilson struct i915_gem_context *ctx; 248112ed2d3SChris Wilson struct i915_request *rq; 249112ed2d3SChris Wilson intel_wakeref_t wakeref; 250112ed2d3SChris Wilson int err = 0; 251112ed2d3SChris Wilson 252112ed2d3SChris Wilson ctx = kernel_context(engine->i915); 253112ed2d3SChris Wilson if (IS_ERR(ctx)) 254112ed2d3SChris Wilson return PTR_ERR(ctx); 255112ed2d3SChris Wilson 256112ed2d3SChris Wilson GEM_BUG_ON(i915_gem_context_is_bannable(ctx)); 257112ed2d3SChris Wilson 258112ed2d3SChris Wilson rq = ERR_PTR(-ENODEV); 259c447ff7dSDaniele Ceraolo Spurio with_intel_runtime_pm(&engine->i915->runtime_pm, wakeref) 260112ed2d3SChris Wilson rq = igt_spinner_create_request(spin, ctx, engine, MI_NOOP); 261112ed2d3SChris Wilson 262112ed2d3SChris Wilson kernel_context_close(ctx); 263112ed2d3SChris Wilson 264112ed2d3SChris Wilson if (IS_ERR(rq)) { 265112ed2d3SChris Wilson spin = NULL; 266112ed2d3SChris Wilson err = PTR_ERR(rq); 267112ed2d3SChris Wilson goto err; 268112ed2d3SChris Wilson } 269112ed2d3SChris Wilson 270112ed2d3SChris Wilson i915_request_add(rq); 271112ed2d3SChris Wilson 272112ed2d3SChris Wilson if (spin && !igt_wait_for_spinner(spin, rq)) { 273112ed2d3SChris Wilson pr_err("Spinner failed to start\n"); 274112ed2d3SChris Wilson err = -ETIMEDOUT; 275112ed2d3SChris Wilson } 276112ed2d3SChris Wilson 277112ed2d3SChris Wilson err: 278112ed2d3SChris Wilson if (err && spin) 279112ed2d3SChris Wilson igt_spinner_end(spin); 280112ed2d3SChris Wilson 281112ed2d3SChris Wilson return err; 282112ed2d3SChris Wilson } 283112ed2d3SChris Wilson 284112ed2d3SChris Wilson static int check_whitelist_across_reset(struct intel_engine_cs *engine, 285112ed2d3SChris Wilson int (*reset)(struct intel_engine_cs *), 286112ed2d3SChris Wilson const char *name) 287112ed2d3SChris Wilson { 288112ed2d3SChris Wilson struct drm_i915_private *i915 = engine->i915; 289112ed2d3SChris Wilson struct i915_gem_context *ctx; 290112ed2d3SChris Wilson struct igt_spinner spin; 291112ed2d3SChris Wilson intel_wakeref_t wakeref; 292112ed2d3SChris Wilson int err; 293112ed2d3SChris Wilson 294112ed2d3SChris Wilson pr_info("Checking %d whitelisted registers (RING_NONPRIV) [%s]\n", 295112ed2d3SChris Wilson engine->whitelist.count, name); 296112ed2d3SChris Wilson 297112ed2d3SChris Wilson err = igt_spinner_init(&spin, i915); 298112ed2d3SChris Wilson if (err) 299112ed2d3SChris Wilson return err; 300112ed2d3SChris Wilson 301112ed2d3SChris Wilson ctx = kernel_context(i915); 302112ed2d3SChris Wilson if (IS_ERR(ctx)) 303112ed2d3SChris Wilson return PTR_ERR(ctx); 304112ed2d3SChris Wilson 305112ed2d3SChris Wilson err = check_whitelist(ctx, engine); 306112ed2d3SChris Wilson if (err) { 307112ed2d3SChris Wilson pr_err("Invalid whitelist *before* %s reset!\n", name); 308112ed2d3SChris Wilson goto out; 309112ed2d3SChris Wilson } 310112ed2d3SChris Wilson 311112ed2d3SChris Wilson err = switch_to_scratch_context(engine, &spin); 312112ed2d3SChris Wilson if (err) 313112ed2d3SChris Wilson goto out; 314112ed2d3SChris Wilson 315c447ff7dSDaniele Ceraolo Spurio with_intel_runtime_pm(&i915->runtime_pm, wakeref) 316112ed2d3SChris Wilson err = reset(engine); 317112ed2d3SChris Wilson 318112ed2d3SChris Wilson igt_spinner_end(&spin); 319112ed2d3SChris Wilson igt_spinner_fini(&spin); 320112ed2d3SChris Wilson 321112ed2d3SChris Wilson if (err) { 322112ed2d3SChris Wilson pr_err("%s reset failed\n", name); 323112ed2d3SChris Wilson goto out; 324112ed2d3SChris Wilson } 325112ed2d3SChris Wilson 326112ed2d3SChris Wilson err = check_whitelist(ctx, engine); 327112ed2d3SChris Wilson if (err) { 328112ed2d3SChris Wilson pr_err("Whitelist not preserved in context across %s reset!\n", 329112ed2d3SChris Wilson name); 330112ed2d3SChris Wilson goto out; 331112ed2d3SChris Wilson } 332112ed2d3SChris Wilson 333112ed2d3SChris Wilson kernel_context_close(ctx); 334112ed2d3SChris Wilson 335112ed2d3SChris Wilson ctx = kernel_context(i915); 336112ed2d3SChris Wilson if (IS_ERR(ctx)) 337112ed2d3SChris Wilson return PTR_ERR(ctx); 338112ed2d3SChris Wilson 339112ed2d3SChris Wilson err = check_whitelist(ctx, engine); 340112ed2d3SChris Wilson if (err) { 341112ed2d3SChris Wilson pr_err("Invalid whitelist *after* %s reset in fresh context!\n", 342112ed2d3SChris Wilson name); 343112ed2d3SChris Wilson goto out; 344112ed2d3SChris Wilson } 345112ed2d3SChris Wilson 346112ed2d3SChris Wilson out: 347112ed2d3SChris Wilson kernel_context_close(ctx); 348112ed2d3SChris Wilson return err; 349112ed2d3SChris Wilson } 350112ed2d3SChris Wilson 351112ed2d3SChris Wilson static struct i915_vma *create_batch(struct i915_gem_context *ctx) 352112ed2d3SChris Wilson { 353112ed2d3SChris Wilson struct drm_i915_gem_object *obj; 354112ed2d3SChris Wilson struct i915_vma *vma; 355112ed2d3SChris Wilson int err; 356112ed2d3SChris Wilson 357112ed2d3SChris Wilson obj = i915_gem_object_create_internal(ctx->i915, 16 * PAGE_SIZE); 358112ed2d3SChris Wilson if (IS_ERR(obj)) 359112ed2d3SChris Wilson return ERR_CAST(obj); 360112ed2d3SChris Wilson 361e568ac38SChris Wilson vma = i915_vma_instance(obj, ctx->vm, NULL); 362112ed2d3SChris Wilson if (IS_ERR(vma)) { 363112ed2d3SChris Wilson err = PTR_ERR(vma); 364112ed2d3SChris Wilson goto err_obj; 365112ed2d3SChris Wilson } 366112ed2d3SChris Wilson 367112ed2d3SChris Wilson err = i915_vma_pin(vma, 0, 0, PIN_USER); 368112ed2d3SChris Wilson if (err) 369112ed2d3SChris Wilson goto err_obj; 370112ed2d3SChris Wilson 371112ed2d3SChris Wilson return vma; 372112ed2d3SChris Wilson 373112ed2d3SChris Wilson err_obj: 374112ed2d3SChris Wilson i915_gem_object_put(obj); 375112ed2d3SChris Wilson return ERR_PTR(err); 376112ed2d3SChris Wilson } 377112ed2d3SChris Wilson 378112ed2d3SChris Wilson static u32 reg_write(u32 old, u32 new, u32 rsvd) 379112ed2d3SChris Wilson { 380112ed2d3SChris Wilson if (rsvd == 0x0000ffff) { 381112ed2d3SChris Wilson old &= ~(new >> 16); 382112ed2d3SChris Wilson old |= new & (new >> 16); 383112ed2d3SChris Wilson } else { 384112ed2d3SChris Wilson old &= ~rsvd; 385112ed2d3SChris Wilson old |= new & rsvd; 386112ed2d3SChris Wilson } 387112ed2d3SChris Wilson 388112ed2d3SChris Wilson return old; 389112ed2d3SChris Wilson } 390112ed2d3SChris Wilson 391112ed2d3SChris Wilson static bool wo_register(struct intel_engine_cs *engine, u32 reg) 392112ed2d3SChris Wilson { 393112ed2d3SChris Wilson enum intel_platform platform = INTEL_INFO(engine->i915)->platform; 394112ed2d3SChris Wilson int i; 395112ed2d3SChris Wilson 396112ed2d3SChris Wilson for (i = 0; i < ARRAY_SIZE(wo_registers); i++) { 397112ed2d3SChris Wilson if (wo_registers[i].platform == platform && 398112ed2d3SChris Wilson wo_registers[i].reg == reg) 399112ed2d3SChris Wilson return true; 400112ed2d3SChris Wilson } 401112ed2d3SChris Wilson 402112ed2d3SChris Wilson return false; 403112ed2d3SChris Wilson } 404112ed2d3SChris Wilson 405767662bcSRobert M. Fosha static bool ro_register(u32 reg) 406767662bcSRobert M. Fosha { 407767662bcSRobert M. Fosha if (reg & RING_FORCE_TO_NONPRIV_RD) 408767662bcSRobert M. Fosha return true; 409767662bcSRobert M. Fosha 410767662bcSRobert M. Fosha return false; 411767662bcSRobert M. Fosha } 412767662bcSRobert M. Fosha 413767662bcSRobert M. Fosha static int whitelist_writable_count(struct intel_engine_cs *engine) 414767662bcSRobert M. Fosha { 415767662bcSRobert M. Fosha int count = engine->whitelist.count; 416767662bcSRobert M. Fosha int i; 417767662bcSRobert M. Fosha 418767662bcSRobert M. Fosha for (i = 0; i < engine->whitelist.count; i++) { 419767662bcSRobert M. Fosha u32 reg = i915_mmio_reg_offset(engine->whitelist.list[i].reg); 420767662bcSRobert M. Fosha 421767662bcSRobert M. Fosha if (ro_register(reg)) 422767662bcSRobert M. Fosha count--; 423767662bcSRobert M. Fosha } 424767662bcSRobert M. Fosha 425767662bcSRobert M. Fosha return count; 426767662bcSRobert M. Fosha } 427767662bcSRobert M. Fosha 428112ed2d3SChris Wilson static int check_dirty_whitelist(struct i915_gem_context *ctx, 429112ed2d3SChris Wilson struct intel_engine_cs *engine) 430112ed2d3SChris Wilson { 431112ed2d3SChris Wilson const u32 values[] = { 432112ed2d3SChris Wilson 0x00000000, 433112ed2d3SChris Wilson 0x01010101, 434112ed2d3SChris Wilson 0x10100101, 435112ed2d3SChris Wilson 0x03030303, 436112ed2d3SChris Wilson 0x30300303, 437112ed2d3SChris Wilson 0x05050505, 438112ed2d3SChris Wilson 0x50500505, 439112ed2d3SChris Wilson 0x0f0f0f0f, 440112ed2d3SChris Wilson 0xf00ff00f, 441112ed2d3SChris Wilson 0x10101010, 442112ed2d3SChris Wilson 0xf0f01010, 443112ed2d3SChris Wilson 0x30303030, 444112ed2d3SChris Wilson 0xa0a03030, 445112ed2d3SChris Wilson 0x50505050, 446112ed2d3SChris Wilson 0xc0c05050, 447112ed2d3SChris Wilson 0xf0f0f0f0, 448112ed2d3SChris Wilson 0x11111111, 449112ed2d3SChris Wilson 0x33333333, 450112ed2d3SChris Wilson 0x55555555, 451112ed2d3SChris Wilson 0x0000ffff, 452112ed2d3SChris Wilson 0x00ff00ff, 453112ed2d3SChris Wilson 0xff0000ff, 454112ed2d3SChris Wilson 0xffff00ff, 455112ed2d3SChris Wilson 0xffffffff, 456112ed2d3SChris Wilson }; 457112ed2d3SChris Wilson struct i915_vma *scratch; 458112ed2d3SChris Wilson struct i915_vma *batch; 459112ed2d3SChris Wilson int err = 0, i, v; 460112ed2d3SChris Wilson u32 *cs, *results; 461112ed2d3SChris Wilson 462e568ac38SChris Wilson scratch = create_scratch(ctx->vm, 2 * ARRAY_SIZE(values) + 1); 463112ed2d3SChris Wilson if (IS_ERR(scratch)) 464112ed2d3SChris Wilson return PTR_ERR(scratch); 465112ed2d3SChris Wilson 466112ed2d3SChris Wilson batch = create_batch(ctx); 467112ed2d3SChris Wilson if (IS_ERR(batch)) { 468112ed2d3SChris Wilson err = PTR_ERR(batch); 469112ed2d3SChris Wilson goto out_scratch; 470112ed2d3SChris Wilson } 471112ed2d3SChris Wilson 472112ed2d3SChris Wilson for (i = 0; i < engine->whitelist.count; i++) { 473112ed2d3SChris Wilson u32 reg = i915_mmio_reg_offset(engine->whitelist.list[i].reg); 474112ed2d3SChris Wilson u64 addr = scratch->node.start; 475112ed2d3SChris Wilson struct i915_request *rq; 476112ed2d3SChris Wilson u32 srm, lrm, rsvd; 477112ed2d3SChris Wilson u32 expect; 478112ed2d3SChris Wilson int idx; 479112ed2d3SChris Wilson 480112ed2d3SChris Wilson if (wo_register(engine, reg)) 481112ed2d3SChris Wilson continue; 482112ed2d3SChris Wilson 483767662bcSRobert M. Fosha if (ro_register(reg)) 484767662bcSRobert M. Fosha continue; 485767662bcSRobert M. Fosha 486112ed2d3SChris Wilson srm = MI_STORE_REGISTER_MEM; 487112ed2d3SChris Wilson lrm = MI_LOAD_REGISTER_MEM; 488112ed2d3SChris Wilson if (INTEL_GEN(ctx->i915) >= 8) 489112ed2d3SChris Wilson lrm++, srm++; 490112ed2d3SChris Wilson 491112ed2d3SChris Wilson pr_debug("%s: Writing garbage to %x\n", 492112ed2d3SChris Wilson engine->name, reg); 493112ed2d3SChris Wilson 494112ed2d3SChris Wilson cs = i915_gem_object_pin_map(batch->obj, I915_MAP_WC); 495112ed2d3SChris Wilson if (IS_ERR(cs)) { 496112ed2d3SChris Wilson err = PTR_ERR(cs); 497112ed2d3SChris Wilson goto out_batch; 498112ed2d3SChris Wilson } 499112ed2d3SChris Wilson 500112ed2d3SChris Wilson /* SRM original */ 501112ed2d3SChris Wilson *cs++ = srm; 502112ed2d3SChris Wilson *cs++ = reg; 503112ed2d3SChris Wilson *cs++ = lower_32_bits(addr); 504112ed2d3SChris Wilson *cs++ = upper_32_bits(addr); 505112ed2d3SChris Wilson 506112ed2d3SChris Wilson idx = 1; 507112ed2d3SChris Wilson for (v = 0; v < ARRAY_SIZE(values); v++) { 508112ed2d3SChris Wilson /* LRI garbage */ 509112ed2d3SChris Wilson *cs++ = MI_LOAD_REGISTER_IMM(1); 510112ed2d3SChris Wilson *cs++ = reg; 511112ed2d3SChris Wilson *cs++ = values[v]; 512112ed2d3SChris Wilson 513112ed2d3SChris Wilson /* SRM result */ 514112ed2d3SChris Wilson *cs++ = srm; 515112ed2d3SChris Wilson *cs++ = reg; 516112ed2d3SChris Wilson *cs++ = lower_32_bits(addr + sizeof(u32) * idx); 517112ed2d3SChris Wilson *cs++ = upper_32_bits(addr + sizeof(u32) * idx); 518112ed2d3SChris Wilson idx++; 519112ed2d3SChris Wilson } 520112ed2d3SChris Wilson for (v = 0; v < ARRAY_SIZE(values); v++) { 521112ed2d3SChris Wilson /* LRI garbage */ 522112ed2d3SChris Wilson *cs++ = MI_LOAD_REGISTER_IMM(1); 523112ed2d3SChris Wilson *cs++ = reg; 524112ed2d3SChris Wilson *cs++ = ~values[v]; 525112ed2d3SChris Wilson 526112ed2d3SChris Wilson /* SRM result */ 527112ed2d3SChris Wilson *cs++ = srm; 528112ed2d3SChris Wilson *cs++ = reg; 529112ed2d3SChris Wilson *cs++ = lower_32_bits(addr + sizeof(u32) * idx); 530112ed2d3SChris Wilson *cs++ = upper_32_bits(addr + sizeof(u32) * idx); 531112ed2d3SChris Wilson idx++; 532112ed2d3SChris Wilson } 533112ed2d3SChris Wilson GEM_BUG_ON(idx * sizeof(u32) > scratch->size); 534112ed2d3SChris Wilson 535112ed2d3SChris Wilson /* LRM original -- don't leave garbage in the context! */ 536112ed2d3SChris Wilson *cs++ = lrm; 537112ed2d3SChris Wilson *cs++ = reg; 538112ed2d3SChris Wilson *cs++ = lower_32_bits(addr); 539112ed2d3SChris Wilson *cs++ = upper_32_bits(addr); 540112ed2d3SChris Wilson 541112ed2d3SChris Wilson *cs++ = MI_BATCH_BUFFER_END; 542112ed2d3SChris Wilson 543112ed2d3SChris Wilson i915_gem_object_flush_map(batch->obj); 544112ed2d3SChris Wilson i915_gem_object_unpin_map(batch->obj); 545112ed2d3SChris Wilson i915_gem_chipset_flush(ctx->i915); 546112ed2d3SChris Wilson 54746472b3eSChris Wilson rq = igt_request_alloc(ctx, engine); 548112ed2d3SChris Wilson if (IS_ERR(rq)) { 549112ed2d3SChris Wilson err = PTR_ERR(rq); 550112ed2d3SChris Wilson goto out_batch; 551112ed2d3SChris Wilson } 552112ed2d3SChris Wilson 553112ed2d3SChris Wilson if (engine->emit_init_breadcrumb) { /* Be nice if we hang */ 554112ed2d3SChris Wilson err = engine->emit_init_breadcrumb(rq); 555112ed2d3SChris Wilson if (err) 556112ed2d3SChris Wilson goto err_request; 557112ed2d3SChris Wilson } 558112ed2d3SChris Wilson 559112ed2d3SChris Wilson err = engine->emit_bb_start(rq, 560112ed2d3SChris Wilson batch->node.start, PAGE_SIZE, 561112ed2d3SChris Wilson 0); 562112ed2d3SChris Wilson if (err) 563112ed2d3SChris Wilson goto err_request; 564112ed2d3SChris Wilson 565112ed2d3SChris Wilson err_request: 566112ed2d3SChris Wilson i915_request_add(rq); 567112ed2d3SChris Wilson if (err) 568112ed2d3SChris Wilson goto out_batch; 569112ed2d3SChris Wilson 570112ed2d3SChris Wilson if (i915_request_wait(rq, I915_WAIT_LOCKED, HZ / 5) < 0) { 571112ed2d3SChris Wilson pr_err("%s: Futzing %x timedout; cancelling test\n", 572112ed2d3SChris Wilson engine->name, reg); 573112ed2d3SChris Wilson i915_gem_set_wedged(ctx->i915); 574112ed2d3SChris Wilson err = -EIO; 575112ed2d3SChris Wilson goto out_batch; 576112ed2d3SChris Wilson } 577112ed2d3SChris Wilson 578112ed2d3SChris Wilson results = i915_gem_object_pin_map(scratch->obj, I915_MAP_WB); 579112ed2d3SChris Wilson if (IS_ERR(results)) { 580112ed2d3SChris Wilson err = PTR_ERR(results); 581112ed2d3SChris Wilson goto out_batch; 582112ed2d3SChris Wilson } 583112ed2d3SChris Wilson 584112ed2d3SChris Wilson GEM_BUG_ON(values[ARRAY_SIZE(values) - 1] != 0xffffffff); 585112ed2d3SChris Wilson rsvd = results[ARRAY_SIZE(values)]; /* detect write masking */ 586112ed2d3SChris Wilson if (!rsvd) { 587112ed2d3SChris Wilson pr_err("%s: Unable to write to whitelisted register %x\n", 588112ed2d3SChris Wilson engine->name, reg); 589112ed2d3SChris Wilson err = -EINVAL; 590112ed2d3SChris Wilson goto out_unpin; 591112ed2d3SChris Wilson } 592112ed2d3SChris Wilson 593112ed2d3SChris Wilson expect = results[0]; 594112ed2d3SChris Wilson idx = 1; 595112ed2d3SChris Wilson for (v = 0; v < ARRAY_SIZE(values); v++) { 596112ed2d3SChris Wilson expect = reg_write(expect, values[v], rsvd); 597112ed2d3SChris Wilson if (results[idx] != expect) 598112ed2d3SChris Wilson err++; 599112ed2d3SChris Wilson idx++; 600112ed2d3SChris Wilson } 601112ed2d3SChris Wilson for (v = 0; v < ARRAY_SIZE(values); v++) { 602112ed2d3SChris Wilson expect = reg_write(expect, ~values[v], rsvd); 603112ed2d3SChris Wilson if (results[idx] != expect) 604112ed2d3SChris Wilson err++; 605112ed2d3SChris Wilson idx++; 606112ed2d3SChris Wilson } 607112ed2d3SChris Wilson if (err) { 608112ed2d3SChris Wilson pr_err("%s: %d mismatch between values written to whitelisted register [%x], and values read back!\n", 609112ed2d3SChris Wilson engine->name, err, reg); 610112ed2d3SChris Wilson 611112ed2d3SChris Wilson pr_info("%s: Whitelisted register: %x, original value %08x, rsvd %08x\n", 612112ed2d3SChris Wilson engine->name, reg, results[0], rsvd); 613112ed2d3SChris Wilson 614112ed2d3SChris Wilson expect = results[0]; 615112ed2d3SChris Wilson idx = 1; 616112ed2d3SChris Wilson for (v = 0; v < ARRAY_SIZE(values); v++) { 617112ed2d3SChris Wilson u32 w = values[v]; 618112ed2d3SChris Wilson 619112ed2d3SChris Wilson expect = reg_write(expect, w, rsvd); 620112ed2d3SChris Wilson pr_info("Wrote %08x, read %08x, expect %08x\n", 621112ed2d3SChris Wilson w, results[idx], expect); 622112ed2d3SChris Wilson idx++; 623112ed2d3SChris Wilson } 624112ed2d3SChris Wilson for (v = 0; v < ARRAY_SIZE(values); v++) { 625112ed2d3SChris Wilson u32 w = ~values[v]; 626112ed2d3SChris Wilson 627112ed2d3SChris Wilson expect = reg_write(expect, w, rsvd); 628112ed2d3SChris Wilson pr_info("Wrote %08x, read %08x, expect %08x\n", 629112ed2d3SChris Wilson w, results[idx], expect); 630112ed2d3SChris Wilson idx++; 631112ed2d3SChris Wilson } 632112ed2d3SChris Wilson 633112ed2d3SChris Wilson err = -EINVAL; 634112ed2d3SChris Wilson } 635112ed2d3SChris Wilson out_unpin: 636112ed2d3SChris Wilson i915_gem_object_unpin_map(scratch->obj); 637112ed2d3SChris Wilson if (err) 638112ed2d3SChris Wilson break; 639112ed2d3SChris Wilson } 640112ed2d3SChris Wilson 641112ed2d3SChris Wilson if (igt_flush_test(ctx->i915, I915_WAIT_LOCKED)) 642112ed2d3SChris Wilson err = -EIO; 643112ed2d3SChris Wilson out_batch: 644112ed2d3SChris Wilson i915_vma_unpin_and_release(&batch, 0); 645112ed2d3SChris Wilson out_scratch: 646112ed2d3SChris Wilson i915_vma_unpin_and_release(&scratch, 0); 647112ed2d3SChris Wilson return err; 648112ed2d3SChris Wilson } 649112ed2d3SChris Wilson 650112ed2d3SChris Wilson static int live_dirty_whitelist(void *arg) 651112ed2d3SChris Wilson { 652112ed2d3SChris Wilson struct drm_i915_private *i915 = arg; 653112ed2d3SChris Wilson struct intel_engine_cs *engine; 654112ed2d3SChris Wilson struct i915_gem_context *ctx; 655112ed2d3SChris Wilson enum intel_engine_id id; 656112ed2d3SChris Wilson intel_wakeref_t wakeref; 657112ed2d3SChris Wilson struct drm_file *file; 658112ed2d3SChris Wilson int err = 0; 659112ed2d3SChris Wilson 660112ed2d3SChris Wilson /* Can the user write to the whitelisted registers? */ 661112ed2d3SChris Wilson 662112ed2d3SChris Wilson if (INTEL_GEN(i915) < 7) /* minimum requirement for LRI, SRM, LRM */ 663112ed2d3SChris Wilson return 0; 664112ed2d3SChris Wilson 665d858d569SDaniele Ceraolo Spurio wakeref = intel_runtime_pm_get(&i915->runtime_pm); 666112ed2d3SChris Wilson 667112ed2d3SChris Wilson mutex_unlock(&i915->drm.struct_mutex); 668112ed2d3SChris Wilson file = mock_file(i915); 669112ed2d3SChris Wilson mutex_lock(&i915->drm.struct_mutex); 670112ed2d3SChris Wilson if (IS_ERR(file)) { 671112ed2d3SChris Wilson err = PTR_ERR(file); 672112ed2d3SChris Wilson goto out_rpm; 673112ed2d3SChris Wilson } 674112ed2d3SChris Wilson 675112ed2d3SChris Wilson ctx = live_context(i915, file); 676112ed2d3SChris Wilson if (IS_ERR(ctx)) { 677112ed2d3SChris Wilson err = PTR_ERR(ctx); 678112ed2d3SChris Wilson goto out_file; 679112ed2d3SChris Wilson } 680112ed2d3SChris Wilson 681112ed2d3SChris Wilson for_each_engine(engine, i915, id) { 682112ed2d3SChris Wilson if (engine->whitelist.count == 0) 683112ed2d3SChris Wilson continue; 684112ed2d3SChris Wilson 685112ed2d3SChris Wilson err = check_dirty_whitelist(ctx, engine); 686112ed2d3SChris Wilson if (err) 687112ed2d3SChris Wilson goto out_file; 688112ed2d3SChris Wilson } 689112ed2d3SChris Wilson 690112ed2d3SChris Wilson out_file: 691112ed2d3SChris Wilson mutex_unlock(&i915->drm.struct_mutex); 692112ed2d3SChris Wilson mock_file_free(i915, file); 693112ed2d3SChris Wilson mutex_lock(&i915->drm.struct_mutex); 694112ed2d3SChris Wilson out_rpm: 695d858d569SDaniele Ceraolo Spurio intel_runtime_pm_put(&i915->runtime_pm, wakeref); 696112ed2d3SChris Wilson return err; 697112ed2d3SChris Wilson } 698112ed2d3SChris Wilson 699112ed2d3SChris Wilson static int live_reset_whitelist(void *arg) 700112ed2d3SChris Wilson { 701112ed2d3SChris Wilson struct drm_i915_private *i915 = arg; 702112ed2d3SChris Wilson struct intel_engine_cs *engine = i915->engine[RCS0]; 703112ed2d3SChris Wilson int err = 0; 704112ed2d3SChris Wilson 705112ed2d3SChris Wilson /* If we reset the gpu, we should not lose the RING_NONPRIV */ 706112ed2d3SChris Wilson 707112ed2d3SChris Wilson if (!engine || engine->whitelist.count == 0) 708112ed2d3SChris Wilson return 0; 709112ed2d3SChris Wilson 710112ed2d3SChris Wilson igt_global_reset_lock(i915); 711112ed2d3SChris Wilson 712112ed2d3SChris Wilson if (intel_has_reset_engine(i915)) { 713112ed2d3SChris Wilson err = check_whitelist_across_reset(engine, 714112ed2d3SChris Wilson do_engine_reset, 715112ed2d3SChris Wilson "engine"); 716112ed2d3SChris Wilson if (err) 717112ed2d3SChris Wilson goto out; 718112ed2d3SChris Wilson } 719112ed2d3SChris Wilson 720112ed2d3SChris Wilson if (intel_has_gpu_reset(i915)) { 721112ed2d3SChris Wilson err = check_whitelist_across_reset(engine, 722112ed2d3SChris Wilson do_device_reset, 723112ed2d3SChris Wilson "device"); 724112ed2d3SChris Wilson if (err) 725112ed2d3SChris Wilson goto out; 726112ed2d3SChris Wilson } 727112ed2d3SChris Wilson 728112ed2d3SChris Wilson out: 729112ed2d3SChris Wilson igt_global_reset_unlock(i915); 730112ed2d3SChris Wilson return err; 731112ed2d3SChris Wilson } 732112ed2d3SChris Wilson 733112ed2d3SChris Wilson static int read_whitelisted_registers(struct i915_gem_context *ctx, 734112ed2d3SChris Wilson struct intel_engine_cs *engine, 735112ed2d3SChris Wilson struct i915_vma *results) 736112ed2d3SChris Wilson { 737112ed2d3SChris Wilson struct i915_request *rq; 738112ed2d3SChris Wilson int i, err = 0; 739112ed2d3SChris Wilson u32 srm, *cs; 740112ed2d3SChris Wilson 74146472b3eSChris Wilson rq = igt_request_alloc(ctx, engine); 742112ed2d3SChris Wilson if (IS_ERR(rq)) 743112ed2d3SChris Wilson return PTR_ERR(rq); 744112ed2d3SChris Wilson 745112ed2d3SChris Wilson srm = MI_STORE_REGISTER_MEM; 746112ed2d3SChris Wilson if (INTEL_GEN(ctx->i915) >= 8) 747112ed2d3SChris Wilson srm++; 748112ed2d3SChris Wilson 749112ed2d3SChris Wilson cs = intel_ring_begin(rq, 4 * engine->whitelist.count); 750112ed2d3SChris Wilson if (IS_ERR(cs)) { 751112ed2d3SChris Wilson err = PTR_ERR(cs); 752112ed2d3SChris Wilson goto err_req; 753112ed2d3SChris Wilson } 754112ed2d3SChris Wilson 755112ed2d3SChris Wilson for (i = 0; i < engine->whitelist.count; i++) { 756112ed2d3SChris Wilson u64 offset = results->node.start + sizeof(u32) * i; 757767662bcSRobert M. Fosha u32 reg = i915_mmio_reg_offset(engine->whitelist.list[i].reg); 758767662bcSRobert M. Fosha 759767662bcSRobert M. Fosha /* Clear RD only and WR only flags */ 760767662bcSRobert M. Fosha reg &= ~(RING_FORCE_TO_NONPRIV_RD | RING_FORCE_TO_NONPRIV_WR); 761112ed2d3SChris Wilson 762112ed2d3SChris Wilson *cs++ = srm; 763767662bcSRobert M. Fosha *cs++ = reg; 764112ed2d3SChris Wilson *cs++ = lower_32_bits(offset); 765112ed2d3SChris Wilson *cs++ = upper_32_bits(offset); 766112ed2d3SChris Wilson } 767112ed2d3SChris Wilson intel_ring_advance(rq, cs); 768112ed2d3SChris Wilson 769112ed2d3SChris Wilson err_req: 770112ed2d3SChris Wilson i915_request_add(rq); 771112ed2d3SChris Wilson 772112ed2d3SChris Wilson if (i915_request_wait(rq, I915_WAIT_LOCKED, HZ / 5) < 0) 773112ed2d3SChris Wilson err = -EIO; 774112ed2d3SChris Wilson 775112ed2d3SChris Wilson return err; 776112ed2d3SChris Wilson } 777112ed2d3SChris Wilson 778112ed2d3SChris Wilson static int scrub_whitelisted_registers(struct i915_gem_context *ctx, 779112ed2d3SChris Wilson struct intel_engine_cs *engine) 780112ed2d3SChris Wilson { 781112ed2d3SChris Wilson struct i915_request *rq; 782112ed2d3SChris Wilson struct i915_vma *batch; 783112ed2d3SChris Wilson int i, err = 0; 784112ed2d3SChris Wilson u32 *cs; 785112ed2d3SChris Wilson 786112ed2d3SChris Wilson batch = create_batch(ctx); 787112ed2d3SChris Wilson if (IS_ERR(batch)) 788112ed2d3SChris Wilson return PTR_ERR(batch); 789112ed2d3SChris Wilson 790112ed2d3SChris Wilson cs = i915_gem_object_pin_map(batch->obj, I915_MAP_WC); 791112ed2d3SChris Wilson if (IS_ERR(cs)) { 792112ed2d3SChris Wilson err = PTR_ERR(cs); 793112ed2d3SChris Wilson goto err_batch; 794112ed2d3SChris Wilson } 795112ed2d3SChris Wilson 796767662bcSRobert M. Fosha *cs++ = MI_LOAD_REGISTER_IMM(whitelist_writable_count(engine)); 797112ed2d3SChris Wilson for (i = 0; i < engine->whitelist.count; i++) { 798767662bcSRobert M. Fosha u32 reg = i915_mmio_reg_offset(engine->whitelist.list[i].reg); 799767662bcSRobert M. Fosha 800767662bcSRobert M. Fosha if (ro_register(reg)) 801767662bcSRobert M. Fosha continue; 802767662bcSRobert M. Fosha 803767662bcSRobert M. Fosha *cs++ = reg; 804112ed2d3SChris Wilson *cs++ = 0xffffffff; 805112ed2d3SChris Wilson } 806112ed2d3SChris Wilson *cs++ = MI_BATCH_BUFFER_END; 807112ed2d3SChris Wilson 808112ed2d3SChris Wilson i915_gem_object_flush_map(batch->obj); 809112ed2d3SChris Wilson i915_gem_chipset_flush(ctx->i915); 810112ed2d3SChris Wilson 81146472b3eSChris Wilson rq = igt_request_alloc(ctx, engine); 812112ed2d3SChris Wilson if (IS_ERR(rq)) { 813112ed2d3SChris Wilson err = PTR_ERR(rq); 814112ed2d3SChris Wilson goto err_unpin; 815112ed2d3SChris Wilson } 816112ed2d3SChris Wilson 817112ed2d3SChris Wilson if (engine->emit_init_breadcrumb) { /* Be nice if we hang */ 818112ed2d3SChris Wilson err = engine->emit_init_breadcrumb(rq); 819112ed2d3SChris Wilson if (err) 820112ed2d3SChris Wilson goto err_request; 821112ed2d3SChris Wilson } 822112ed2d3SChris Wilson 823112ed2d3SChris Wilson /* Perform the writes from an unprivileged "user" batch */ 824112ed2d3SChris Wilson err = engine->emit_bb_start(rq, batch->node.start, 0, 0); 825112ed2d3SChris Wilson 826112ed2d3SChris Wilson err_request: 827112ed2d3SChris Wilson i915_request_add(rq); 828112ed2d3SChris Wilson if (i915_request_wait(rq, I915_WAIT_LOCKED, HZ / 5) < 0) 829112ed2d3SChris Wilson err = -EIO; 830112ed2d3SChris Wilson 831112ed2d3SChris Wilson err_unpin: 832112ed2d3SChris Wilson i915_gem_object_unpin_map(batch->obj); 833112ed2d3SChris Wilson err_batch: 834112ed2d3SChris Wilson i915_vma_unpin_and_release(&batch, 0); 835112ed2d3SChris Wilson return err; 836112ed2d3SChris Wilson } 837112ed2d3SChris Wilson 838112ed2d3SChris Wilson struct regmask { 839112ed2d3SChris Wilson i915_reg_t reg; 840112ed2d3SChris Wilson unsigned long gen_mask; 841112ed2d3SChris Wilson }; 842112ed2d3SChris Wilson 843112ed2d3SChris Wilson static bool find_reg(struct drm_i915_private *i915, 844112ed2d3SChris Wilson i915_reg_t reg, 845112ed2d3SChris Wilson const struct regmask *tbl, 846112ed2d3SChris Wilson unsigned long count) 847112ed2d3SChris Wilson { 848112ed2d3SChris Wilson u32 offset = i915_mmio_reg_offset(reg); 849112ed2d3SChris Wilson 850112ed2d3SChris Wilson while (count--) { 851112ed2d3SChris Wilson if (INTEL_INFO(i915)->gen_mask & tbl->gen_mask && 852112ed2d3SChris Wilson i915_mmio_reg_offset(tbl->reg) == offset) 853112ed2d3SChris Wilson return true; 854112ed2d3SChris Wilson tbl++; 855112ed2d3SChris Wilson } 856112ed2d3SChris Wilson 857112ed2d3SChris Wilson return false; 858112ed2d3SChris Wilson } 859112ed2d3SChris Wilson 860112ed2d3SChris Wilson static bool pardon_reg(struct drm_i915_private *i915, i915_reg_t reg) 861112ed2d3SChris Wilson { 862112ed2d3SChris Wilson /* Alas, we must pardon some whitelists. Mistakes already made */ 863112ed2d3SChris Wilson static const struct regmask pardon[] = { 864112ed2d3SChris Wilson { GEN9_CTX_PREEMPT_REG, INTEL_GEN_MASK(9, 9) }, 865112ed2d3SChris Wilson { GEN8_L3SQCREG4, INTEL_GEN_MASK(9, 9) }, 866112ed2d3SChris Wilson }; 867112ed2d3SChris Wilson 868112ed2d3SChris Wilson return find_reg(i915, reg, pardon, ARRAY_SIZE(pardon)); 869112ed2d3SChris Wilson } 870112ed2d3SChris Wilson 871112ed2d3SChris Wilson static bool result_eq(struct intel_engine_cs *engine, 872112ed2d3SChris Wilson u32 a, u32 b, i915_reg_t reg) 873112ed2d3SChris Wilson { 874112ed2d3SChris Wilson if (a != b && !pardon_reg(engine->i915, reg)) { 875112ed2d3SChris Wilson pr_err("Whitelisted register 0x%4x not context saved: A=%08x, B=%08x\n", 876112ed2d3SChris Wilson i915_mmio_reg_offset(reg), a, b); 877112ed2d3SChris Wilson return false; 878112ed2d3SChris Wilson } 879112ed2d3SChris Wilson 880112ed2d3SChris Wilson return true; 881112ed2d3SChris Wilson } 882112ed2d3SChris Wilson 883112ed2d3SChris Wilson static bool writeonly_reg(struct drm_i915_private *i915, i915_reg_t reg) 884112ed2d3SChris Wilson { 885112ed2d3SChris Wilson /* Some registers do not seem to behave and our writes unreadable */ 886112ed2d3SChris Wilson static const struct regmask wo[] = { 887112ed2d3SChris Wilson { GEN9_SLICE_COMMON_ECO_CHICKEN1, INTEL_GEN_MASK(9, 9) }, 888112ed2d3SChris Wilson }; 889112ed2d3SChris Wilson 890112ed2d3SChris Wilson return find_reg(i915, reg, wo, ARRAY_SIZE(wo)); 891112ed2d3SChris Wilson } 892112ed2d3SChris Wilson 893112ed2d3SChris Wilson static bool result_neq(struct intel_engine_cs *engine, 894112ed2d3SChris Wilson u32 a, u32 b, i915_reg_t reg) 895112ed2d3SChris Wilson { 896112ed2d3SChris Wilson if (a == b && !writeonly_reg(engine->i915, reg)) { 897112ed2d3SChris Wilson pr_err("Whitelist register 0x%4x:%08x was unwritable\n", 898112ed2d3SChris Wilson i915_mmio_reg_offset(reg), a); 899112ed2d3SChris Wilson return false; 900112ed2d3SChris Wilson } 901112ed2d3SChris Wilson 902112ed2d3SChris Wilson return true; 903112ed2d3SChris Wilson } 904112ed2d3SChris Wilson 905112ed2d3SChris Wilson static int 906112ed2d3SChris Wilson check_whitelisted_registers(struct intel_engine_cs *engine, 907112ed2d3SChris Wilson struct i915_vma *A, 908112ed2d3SChris Wilson struct i915_vma *B, 909112ed2d3SChris Wilson bool (*fn)(struct intel_engine_cs *engine, 910112ed2d3SChris Wilson u32 a, u32 b, 911112ed2d3SChris Wilson i915_reg_t reg)) 912112ed2d3SChris Wilson { 913112ed2d3SChris Wilson u32 *a, *b; 914112ed2d3SChris Wilson int i, err; 915112ed2d3SChris Wilson 916112ed2d3SChris Wilson a = i915_gem_object_pin_map(A->obj, I915_MAP_WB); 917112ed2d3SChris Wilson if (IS_ERR(a)) 918112ed2d3SChris Wilson return PTR_ERR(a); 919112ed2d3SChris Wilson 920112ed2d3SChris Wilson b = i915_gem_object_pin_map(B->obj, I915_MAP_WB); 921112ed2d3SChris Wilson if (IS_ERR(b)) { 922112ed2d3SChris Wilson err = PTR_ERR(b); 923112ed2d3SChris Wilson goto err_a; 924112ed2d3SChris Wilson } 925112ed2d3SChris Wilson 926112ed2d3SChris Wilson err = 0; 927112ed2d3SChris Wilson for (i = 0; i < engine->whitelist.count; i++) { 928112ed2d3SChris Wilson if (!fn(engine, a[i], b[i], engine->whitelist.list[i].reg)) 929112ed2d3SChris Wilson err = -EINVAL; 930112ed2d3SChris Wilson } 931112ed2d3SChris Wilson 932112ed2d3SChris Wilson i915_gem_object_unpin_map(B->obj); 933112ed2d3SChris Wilson err_a: 934112ed2d3SChris Wilson i915_gem_object_unpin_map(A->obj); 935112ed2d3SChris Wilson return err; 936112ed2d3SChris Wilson } 937112ed2d3SChris Wilson 938112ed2d3SChris Wilson static int live_isolated_whitelist(void *arg) 939112ed2d3SChris Wilson { 940112ed2d3SChris Wilson struct drm_i915_private *i915 = arg; 941112ed2d3SChris Wilson struct { 942112ed2d3SChris Wilson struct i915_gem_context *ctx; 943112ed2d3SChris Wilson struct i915_vma *scratch[2]; 944112ed2d3SChris Wilson } client[2] = {}; 945112ed2d3SChris Wilson struct intel_engine_cs *engine; 946112ed2d3SChris Wilson enum intel_engine_id id; 947112ed2d3SChris Wilson int i, err = 0; 948112ed2d3SChris Wilson 949112ed2d3SChris Wilson /* 950112ed2d3SChris Wilson * Check that a write into a whitelist register works, but 951112ed2d3SChris Wilson * invisible to a second context. 952112ed2d3SChris Wilson */ 953112ed2d3SChris Wilson 954112ed2d3SChris Wilson if (!intel_engines_has_context_isolation(i915)) 955112ed2d3SChris Wilson return 0; 956112ed2d3SChris Wilson 957e568ac38SChris Wilson if (!i915->kernel_context->vm) 958112ed2d3SChris Wilson return 0; 959112ed2d3SChris Wilson 960112ed2d3SChris Wilson for (i = 0; i < ARRAY_SIZE(client); i++) { 961112ed2d3SChris Wilson struct i915_gem_context *c; 962112ed2d3SChris Wilson 963112ed2d3SChris Wilson c = kernel_context(i915); 964112ed2d3SChris Wilson if (IS_ERR(c)) { 965112ed2d3SChris Wilson err = PTR_ERR(c); 966112ed2d3SChris Wilson goto err; 967112ed2d3SChris Wilson } 968112ed2d3SChris Wilson 969e568ac38SChris Wilson client[i].scratch[0] = create_scratch(c->vm, 1024); 970112ed2d3SChris Wilson if (IS_ERR(client[i].scratch[0])) { 971112ed2d3SChris Wilson err = PTR_ERR(client[i].scratch[0]); 972112ed2d3SChris Wilson kernel_context_close(c); 973112ed2d3SChris Wilson goto err; 974112ed2d3SChris Wilson } 975112ed2d3SChris Wilson 976e568ac38SChris Wilson client[i].scratch[1] = create_scratch(c->vm, 1024); 977112ed2d3SChris Wilson if (IS_ERR(client[i].scratch[1])) { 978112ed2d3SChris Wilson err = PTR_ERR(client[i].scratch[1]); 979112ed2d3SChris Wilson i915_vma_unpin_and_release(&client[i].scratch[0], 0); 980112ed2d3SChris Wilson kernel_context_close(c); 981112ed2d3SChris Wilson goto err; 982112ed2d3SChris Wilson } 983112ed2d3SChris Wilson 984112ed2d3SChris Wilson client[i].ctx = c; 985112ed2d3SChris Wilson } 986112ed2d3SChris Wilson 987112ed2d3SChris Wilson for_each_engine(engine, i915, id) { 988767662bcSRobert M. Fosha if (!whitelist_writable_count(engine)) 989112ed2d3SChris Wilson continue; 990112ed2d3SChris Wilson 991112ed2d3SChris Wilson /* Read default values */ 992112ed2d3SChris Wilson err = read_whitelisted_registers(client[0].ctx, engine, 993112ed2d3SChris Wilson client[0].scratch[0]); 994112ed2d3SChris Wilson if (err) 995112ed2d3SChris Wilson goto err; 996112ed2d3SChris Wilson 997112ed2d3SChris Wilson /* Try to overwrite registers (should only affect ctx0) */ 998112ed2d3SChris Wilson err = scrub_whitelisted_registers(client[0].ctx, engine); 999112ed2d3SChris Wilson if (err) 1000112ed2d3SChris Wilson goto err; 1001112ed2d3SChris Wilson 1002112ed2d3SChris Wilson /* Read values from ctx1, we expect these to be defaults */ 1003112ed2d3SChris Wilson err = read_whitelisted_registers(client[1].ctx, engine, 1004112ed2d3SChris Wilson client[1].scratch[0]); 1005112ed2d3SChris Wilson if (err) 1006112ed2d3SChris Wilson goto err; 1007112ed2d3SChris Wilson 1008112ed2d3SChris Wilson /* Verify that both reads return the same default values */ 1009112ed2d3SChris Wilson err = check_whitelisted_registers(engine, 1010112ed2d3SChris Wilson client[0].scratch[0], 1011112ed2d3SChris Wilson client[1].scratch[0], 1012112ed2d3SChris Wilson result_eq); 1013112ed2d3SChris Wilson if (err) 1014112ed2d3SChris Wilson goto err; 1015112ed2d3SChris Wilson 1016112ed2d3SChris Wilson /* Read back the updated values in ctx0 */ 1017112ed2d3SChris Wilson err = read_whitelisted_registers(client[0].ctx, engine, 1018112ed2d3SChris Wilson client[0].scratch[1]); 1019112ed2d3SChris Wilson if (err) 1020112ed2d3SChris Wilson goto err; 1021112ed2d3SChris Wilson 1022112ed2d3SChris Wilson /* User should be granted privilege to overwhite regs */ 1023112ed2d3SChris Wilson err = check_whitelisted_registers(engine, 1024112ed2d3SChris Wilson client[0].scratch[0], 1025112ed2d3SChris Wilson client[0].scratch[1], 1026112ed2d3SChris Wilson result_neq); 1027112ed2d3SChris Wilson if (err) 1028112ed2d3SChris Wilson goto err; 1029112ed2d3SChris Wilson } 1030112ed2d3SChris Wilson 1031112ed2d3SChris Wilson err: 1032112ed2d3SChris Wilson for (i = 0; i < ARRAY_SIZE(client); i++) { 1033112ed2d3SChris Wilson if (!client[i].ctx) 1034112ed2d3SChris Wilson break; 1035112ed2d3SChris Wilson 1036112ed2d3SChris Wilson i915_vma_unpin_and_release(&client[i].scratch[1], 0); 1037112ed2d3SChris Wilson i915_vma_unpin_and_release(&client[i].scratch[0], 0); 1038112ed2d3SChris Wilson kernel_context_close(client[i].ctx); 1039112ed2d3SChris Wilson } 1040112ed2d3SChris Wilson 1041112ed2d3SChris Wilson if (igt_flush_test(i915, I915_WAIT_LOCKED)) 1042112ed2d3SChris Wilson err = -EIO; 1043112ed2d3SChris Wilson 1044112ed2d3SChris Wilson return err; 1045112ed2d3SChris Wilson } 1046112ed2d3SChris Wilson 1047fde93886STvrtko Ursulin static bool 1048fde93886STvrtko Ursulin verify_wa_lists(struct i915_gem_context *ctx, struct wa_lists *lists, 1049fde93886STvrtko Ursulin const char *str) 1050112ed2d3SChris Wilson { 1051fde93886STvrtko Ursulin struct drm_i915_private *i915 = ctx->i915; 1052fde93886STvrtko Ursulin struct i915_gem_engines_iter it; 1053fde93886STvrtko Ursulin struct intel_context *ce; 1054112ed2d3SChris Wilson bool ok = true; 1055112ed2d3SChris Wilson 1056112ed2d3SChris Wilson ok &= wa_list_verify(&i915->uncore, &lists->gt_wa_list, str); 1057112ed2d3SChris Wilson 1058fde93886STvrtko Ursulin for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) { 1059fde93886STvrtko Ursulin enum intel_engine_id id = ce->engine->id; 1060fde93886STvrtko Ursulin 1061fde93886STvrtko Ursulin ok &= engine_wa_list_verify(ce, 1062112ed2d3SChris Wilson &lists->engine[id].wa_list, 1063112ed2d3SChris Wilson str) == 0; 1064fde93886STvrtko Ursulin 1065fde93886STvrtko Ursulin ok &= engine_wa_list_verify(ce, 1066fde93886STvrtko Ursulin &lists->engine[id].ctx_wa_list, 1067fde93886STvrtko Ursulin str) == 0; 1068112ed2d3SChris Wilson } 1069fde93886STvrtko Ursulin i915_gem_context_unlock_engines(ctx); 1070112ed2d3SChris Wilson 1071112ed2d3SChris Wilson return ok; 1072112ed2d3SChris Wilson } 1073112ed2d3SChris Wilson 1074112ed2d3SChris Wilson static int 1075fde93886STvrtko Ursulin live_gpu_reset_workarounds(void *arg) 1076112ed2d3SChris Wilson { 1077112ed2d3SChris Wilson struct drm_i915_private *i915 = arg; 1078fde93886STvrtko Ursulin struct i915_gem_context *ctx; 1079112ed2d3SChris Wilson intel_wakeref_t wakeref; 1080112ed2d3SChris Wilson struct wa_lists lists; 1081112ed2d3SChris Wilson bool ok; 1082112ed2d3SChris Wilson 1083112ed2d3SChris Wilson if (!intel_has_gpu_reset(i915)) 1084112ed2d3SChris Wilson return 0; 1085112ed2d3SChris Wilson 1086fde93886STvrtko Ursulin ctx = kernel_context(i915); 1087fde93886STvrtko Ursulin if (IS_ERR(ctx)) 1088fde93886STvrtko Ursulin return PTR_ERR(ctx); 1089fde93886STvrtko Ursulin 1090112ed2d3SChris Wilson pr_info("Verifying after GPU reset...\n"); 1091112ed2d3SChris Wilson 1092112ed2d3SChris Wilson igt_global_reset_lock(i915); 1093d858d569SDaniele Ceraolo Spurio wakeref = intel_runtime_pm_get(&i915->runtime_pm); 1094112ed2d3SChris Wilson 1095112ed2d3SChris Wilson reference_lists_init(i915, &lists); 1096112ed2d3SChris Wilson 1097fde93886STvrtko Ursulin ok = verify_wa_lists(ctx, &lists, "before reset"); 1098112ed2d3SChris Wilson if (!ok) 1099112ed2d3SChris Wilson goto out; 1100112ed2d3SChris Wilson 1101112ed2d3SChris Wilson i915_reset(i915, ALL_ENGINES, "live_workarounds"); 1102112ed2d3SChris Wilson 1103fde93886STvrtko Ursulin ok = verify_wa_lists(ctx, &lists, "after reset"); 1104112ed2d3SChris Wilson 1105112ed2d3SChris Wilson out: 1106fde93886STvrtko Ursulin kernel_context_close(ctx); 1107112ed2d3SChris Wilson reference_lists_fini(i915, &lists); 1108d858d569SDaniele Ceraolo Spurio intel_runtime_pm_put(&i915->runtime_pm, wakeref); 1109112ed2d3SChris Wilson igt_global_reset_unlock(i915); 1110112ed2d3SChris Wilson 1111112ed2d3SChris Wilson return ok ? 0 : -ESRCH; 1112112ed2d3SChris Wilson } 1113112ed2d3SChris Wilson 1114112ed2d3SChris Wilson static int 1115fde93886STvrtko Ursulin live_engine_reset_workarounds(void *arg) 1116112ed2d3SChris Wilson { 1117112ed2d3SChris Wilson struct drm_i915_private *i915 = arg; 1118112ed2d3SChris Wilson struct intel_engine_cs *engine; 1119112ed2d3SChris Wilson struct i915_gem_context *ctx; 1120112ed2d3SChris Wilson struct igt_spinner spin; 1121112ed2d3SChris Wilson enum intel_engine_id id; 1122112ed2d3SChris Wilson struct i915_request *rq; 1123112ed2d3SChris Wilson intel_wakeref_t wakeref; 1124112ed2d3SChris Wilson struct wa_lists lists; 1125112ed2d3SChris Wilson int ret = 0; 1126112ed2d3SChris Wilson 1127112ed2d3SChris Wilson if (!intel_has_reset_engine(i915)) 1128112ed2d3SChris Wilson return 0; 1129112ed2d3SChris Wilson 1130112ed2d3SChris Wilson ctx = kernel_context(i915); 1131112ed2d3SChris Wilson if (IS_ERR(ctx)) 1132112ed2d3SChris Wilson return PTR_ERR(ctx); 1133112ed2d3SChris Wilson 1134112ed2d3SChris Wilson igt_global_reset_lock(i915); 1135d858d569SDaniele Ceraolo Spurio wakeref = intel_runtime_pm_get(&i915->runtime_pm); 1136112ed2d3SChris Wilson 1137112ed2d3SChris Wilson reference_lists_init(i915, &lists); 1138112ed2d3SChris Wilson 1139112ed2d3SChris Wilson for_each_engine(engine, i915, id) { 1140112ed2d3SChris Wilson bool ok; 1141112ed2d3SChris Wilson 1142112ed2d3SChris Wilson pr_info("Verifying after %s reset...\n", engine->name); 1143112ed2d3SChris Wilson 1144fde93886STvrtko Ursulin ok = verify_wa_lists(ctx, &lists, "before reset"); 1145112ed2d3SChris Wilson if (!ok) { 1146112ed2d3SChris Wilson ret = -ESRCH; 1147112ed2d3SChris Wilson goto err; 1148112ed2d3SChris Wilson } 1149112ed2d3SChris Wilson 1150112ed2d3SChris Wilson i915_reset_engine(engine, "live_workarounds"); 1151112ed2d3SChris Wilson 1152fde93886STvrtko Ursulin ok = verify_wa_lists(ctx, &lists, "after idle reset"); 1153112ed2d3SChris Wilson if (!ok) { 1154112ed2d3SChris Wilson ret = -ESRCH; 1155112ed2d3SChris Wilson goto err; 1156112ed2d3SChris Wilson } 1157112ed2d3SChris Wilson 1158112ed2d3SChris Wilson ret = igt_spinner_init(&spin, i915); 1159112ed2d3SChris Wilson if (ret) 1160112ed2d3SChris Wilson goto err; 1161112ed2d3SChris Wilson 1162112ed2d3SChris Wilson rq = igt_spinner_create_request(&spin, ctx, engine, MI_NOOP); 1163112ed2d3SChris Wilson if (IS_ERR(rq)) { 1164112ed2d3SChris Wilson ret = PTR_ERR(rq); 1165112ed2d3SChris Wilson igt_spinner_fini(&spin); 1166112ed2d3SChris Wilson goto err; 1167112ed2d3SChris Wilson } 1168112ed2d3SChris Wilson 1169112ed2d3SChris Wilson i915_request_add(rq); 1170112ed2d3SChris Wilson 1171112ed2d3SChris Wilson if (!igt_wait_for_spinner(&spin, rq)) { 1172112ed2d3SChris Wilson pr_err("Spinner failed to start\n"); 1173112ed2d3SChris Wilson igt_spinner_fini(&spin); 1174112ed2d3SChris Wilson ret = -ETIMEDOUT; 1175112ed2d3SChris Wilson goto err; 1176112ed2d3SChris Wilson } 1177112ed2d3SChris Wilson 1178112ed2d3SChris Wilson i915_reset_engine(engine, "live_workarounds"); 1179112ed2d3SChris Wilson 1180112ed2d3SChris Wilson igt_spinner_end(&spin); 1181112ed2d3SChris Wilson igt_spinner_fini(&spin); 1182112ed2d3SChris Wilson 1183fde93886STvrtko Ursulin ok = verify_wa_lists(ctx, &lists, "after busy reset"); 1184112ed2d3SChris Wilson if (!ok) { 1185112ed2d3SChris Wilson ret = -ESRCH; 1186112ed2d3SChris Wilson goto err; 1187112ed2d3SChris Wilson } 1188112ed2d3SChris Wilson } 1189112ed2d3SChris Wilson 1190112ed2d3SChris Wilson err: 1191112ed2d3SChris Wilson reference_lists_fini(i915, &lists); 1192d858d569SDaniele Ceraolo Spurio intel_runtime_pm_put(&i915->runtime_pm, wakeref); 1193112ed2d3SChris Wilson igt_global_reset_unlock(i915); 1194112ed2d3SChris Wilson kernel_context_close(ctx); 1195112ed2d3SChris Wilson 1196112ed2d3SChris Wilson igt_flush_test(i915, I915_WAIT_LOCKED); 1197112ed2d3SChris Wilson 1198112ed2d3SChris Wilson return ret; 1199112ed2d3SChris Wilson } 1200112ed2d3SChris Wilson 1201112ed2d3SChris Wilson int intel_workarounds_live_selftests(struct drm_i915_private *i915) 1202112ed2d3SChris Wilson { 1203112ed2d3SChris Wilson static const struct i915_subtest tests[] = { 1204112ed2d3SChris Wilson SUBTEST(live_dirty_whitelist), 1205112ed2d3SChris Wilson SUBTEST(live_reset_whitelist), 1206112ed2d3SChris Wilson SUBTEST(live_isolated_whitelist), 1207fde93886STvrtko Ursulin SUBTEST(live_gpu_reset_workarounds), 1208fde93886STvrtko Ursulin SUBTEST(live_engine_reset_workarounds), 1209112ed2d3SChris Wilson }; 1210112ed2d3SChris Wilson int err; 1211112ed2d3SChris Wilson 1212112ed2d3SChris Wilson if (i915_terminally_wedged(i915)) 1213112ed2d3SChris Wilson return 0; 1214112ed2d3SChris Wilson 1215112ed2d3SChris Wilson mutex_lock(&i915->drm.struct_mutex); 1216112ed2d3SChris Wilson err = i915_subtests(tests, i915); 1217112ed2d3SChris Wilson mutex_unlock(&i915->drm.struct_mutex); 1218112ed2d3SChris Wilson 1219112ed2d3SChris Wilson return err; 1220112ed2d3SChris Wilson } 1221