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" 8750e76b4SChris Wilson #include "gt/intel_engine_user.h" 9baea429dSTvrtko Ursulin #include "gt/intel_gt.h" 10112ed2d3SChris Wilson #include "i915_selftest.h" 11112ed2d3SChris Wilson #include "intel_reset.h" 12112ed2d3SChris Wilson 13112ed2d3SChris Wilson #include "selftests/igt_flush_test.h" 14112ed2d3SChris Wilson #include "selftests/igt_reset.h" 15112ed2d3SChris Wilson #include "selftests/igt_spinner.h" 16112ed2d3SChris Wilson #include "selftests/mock_drm.h" 17112ed2d3SChris Wilson 1810be98a7SChris Wilson #include "gem/selftests/igt_gem_utils.h" 1910be98a7SChris Wilson #include "gem/selftests/mock_context.h" 2010be98a7SChris Wilson 21112ed2d3SChris Wilson static const struct wo_register { 22112ed2d3SChris Wilson enum intel_platform platform; 23112ed2d3SChris Wilson u32 reg; 24112ed2d3SChris Wilson } wo_registers[] = { 25112ed2d3SChris Wilson { INTEL_GEMINILAKE, 0x731c } 26112ed2d3SChris Wilson }; 27112ed2d3SChris Wilson 28112ed2d3SChris Wilson struct wa_lists { 29112ed2d3SChris Wilson struct i915_wa_list gt_wa_list; 30112ed2d3SChris Wilson struct { 31112ed2d3SChris Wilson struct i915_wa_list wa_list; 32fde93886STvrtko Ursulin struct i915_wa_list ctx_wa_list; 33112ed2d3SChris Wilson } engine[I915_NUM_ENGINES]; 34112ed2d3SChris Wilson }; 35112ed2d3SChris Wilson 36112ed2d3SChris Wilson static void 37112ed2d3SChris Wilson reference_lists_init(struct drm_i915_private *i915, struct wa_lists *lists) 38112ed2d3SChris Wilson { 39112ed2d3SChris Wilson struct intel_engine_cs *engine; 40112ed2d3SChris Wilson enum intel_engine_id id; 41112ed2d3SChris Wilson 42112ed2d3SChris Wilson memset(lists, 0, sizeof(*lists)); 43112ed2d3SChris Wilson 443e1f0a51SJohn Harrison wa_init_start(&lists->gt_wa_list, "GT_REF", "global"); 45112ed2d3SChris Wilson gt_init_workarounds(i915, &lists->gt_wa_list); 46112ed2d3SChris Wilson wa_init_finish(&lists->gt_wa_list); 47112ed2d3SChris Wilson 48112ed2d3SChris Wilson for_each_engine(engine, i915, id) { 49112ed2d3SChris Wilson struct i915_wa_list *wal = &lists->engine[id].wa_list; 50112ed2d3SChris Wilson 513e1f0a51SJohn Harrison wa_init_start(wal, "REF", engine->name); 52112ed2d3SChris Wilson engine_init_workarounds(engine, wal); 53112ed2d3SChris Wilson wa_init_finish(wal); 54fde93886STvrtko Ursulin 55fde93886STvrtko Ursulin __intel_engine_init_ctx_wa(engine, 56fde93886STvrtko Ursulin &lists->engine[id].ctx_wa_list, 573e1f0a51SJohn Harrison "CTX_REF"); 58112ed2d3SChris Wilson } 59112ed2d3SChris Wilson } 60112ed2d3SChris Wilson 61112ed2d3SChris Wilson static void 62112ed2d3SChris Wilson reference_lists_fini(struct drm_i915_private *i915, struct wa_lists *lists) 63112ed2d3SChris Wilson { 64112ed2d3SChris Wilson struct intel_engine_cs *engine; 65112ed2d3SChris Wilson enum intel_engine_id id; 66112ed2d3SChris Wilson 67112ed2d3SChris Wilson for_each_engine(engine, i915, id) 68112ed2d3SChris Wilson intel_wa_list_free(&lists->engine[id].wa_list); 69112ed2d3SChris Wilson 70112ed2d3SChris Wilson intel_wa_list_free(&lists->gt_wa_list); 71112ed2d3SChris Wilson } 72112ed2d3SChris Wilson 73112ed2d3SChris Wilson static struct drm_i915_gem_object * 74112ed2d3SChris Wilson read_nonprivs(struct i915_gem_context *ctx, struct intel_engine_cs *engine) 75112ed2d3SChris Wilson { 76112ed2d3SChris Wilson const u32 base = engine->mmio_base; 77112ed2d3SChris Wilson struct drm_i915_gem_object *result; 78112ed2d3SChris Wilson struct i915_request *rq; 79112ed2d3SChris Wilson struct i915_vma *vma; 80112ed2d3SChris Wilson u32 srm, *cs; 81112ed2d3SChris Wilson int err; 82112ed2d3SChris Wilson int i; 83112ed2d3SChris Wilson 84112ed2d3SChris Wilson result = i915_gem_object_create_internal(engine->i915, PAGE_SIZE); 85112ed2d3SChris Wilson if (IS_ERR(result)) 86112ed2d3SChris Wilson return result; 87112ed2d3SChris Wilson 88112ed2d3SChris Wilson i915_gem_object_set_cache_coherency(result, I915_CACHE_LLC); 89112ed2d3SChris Wilson 90112ed2d3SChris Wilson cs = i915_gem_object_pin_map(result, I915_MAP_WB); 91112ed2d3SChris Wilson if (IS_ERR(cs)) { 92112ed2d3SChris Wilson err = PTR_ERR(cs); 93112ed2d3SChris Wilson goto err_obj; 94112ed2d3SChris Wilson } 95112ed2d3SChris Wilson memset(cs, 0xc5, PAGE_SIZE); 96112ed2d3SChris Wilson i915_gem_object_flush_map(result); 97112ed2d3SChris Wilson i915_gem_object_unpin_map(result); 98112ed2d3SChris Wilson 99ba4134a4STvrtko Ursulin vma = i915_vma_instance(result, &engine->gt->ggtt->vm, NULL); 100112ed2d3SChris Wilson if (IS_ERR(vma)) { 101112ed2d3SChris Wilson err = PTR_ERR(vma); 102112ed2d3SChris Wilson goto err_obj; 103112ed2d3SChris Wilson } 104112ed2d3SChris Wilson 105112ed2d3SChris Wilson err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL); 106112ed2d3SChris Wilson if (err) 107112ed2d3SChris Wilson goto err_obj; 108112ed2d3SChris Wilson 10946472b3eSChris Wilson rq = igt_request_alloc(ctx, engine); 110112ed2d3SChris Wilson if (IS_ERR(rq)) { 111112ed2d3SChris Wilson err = PTR_ERR(rq); 112112ed2d3SChris Wilson goto err_pin; 113112ed2d3SChris Wilson } 114112ed2d3SChris Wilson 1156951e589SChris Wilson i915_vma_lock(vma); 11670d6894dSChris Wilson err = i915_request_await_object(rq, vma->obj, true); 11770d6894dSChris Wilson if (err == 0) 118112ed2d3SChris Wilson err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE); 1196951e589SChris Wilson i915_vma_unlock(vma); 120112ed2d3SChris Wilson if (err) 121112ed2d3SChris Wilson goto err_req; 122112ed2d3SChris Wilson 123112ed2d3SChris Wilson srm = MI_STORE_REGISTER_MEM | MI_SRM_LRM_GLOBAL_GTT; 124112ed2d3SChris Wilson if (INTEL_GEN(ctx->i915) >= 8) 125112ed2d3SChris Wilson srm++; 126112ed2d3SChris Wilson 127112ed2d3SChris Wilson cs = intel_ring_begin(rq, 4 * RING_MAX_NONPRIV_SLOTS); 128112ed2d3SChris Wilson if (IS_ERR(cs)) { 129112ed2d3SChris Wilson err = PTR_ERR(cs); 130112ed2d3SChris Wilson goto err_req; 131112ed2d3SChris Wilson } 132112ed2d3SChris Wilson 133112ed2d3SChris Wilson for (i = 0; i < RING_MAX_NONPRIV_SLOTS; i++) { 134112ed2d3SChris Wilson *cs++ = srm; 135112ed2d3SChris Wilson *cs++ = i915_mmio_reg_offset(RING_FORCE_TO_NONPRIV(base, i)); 136112ed2d3SChris Wilson *cs++ = i915_ggtt_offset(vma) + sizeof(u32) * i; 137112ed2d3SChris Wilson *cs++ = 0; 138112ed2d3SChris Wilson } 139112ed2d3SChris Wilson intel_ring_advance(rq, cs); 140112ed2d3SChris Wilson 141112ed2d3SChris Wilson i915_request_add(rq); 142112ed2d3SChris Wilson i915_vma_unpin(vma); 143112ed2d3SChris Wilson 144112ed2d3SChris Wilson return result; 145112ed2d3SChris Wilson 146112ed2d3SChris Wilson err_req: 147112ed2d3SChris Wilson i915_request_add(rq); 148112ed2d3SChris Wilson err_pin: 149112ed2d3SChris Wilson i915_vma_unpin(vma); 150112ed2d3SChris Wilson err_obj: 151112ed2d3SChris Wilson i915_gem_object_put(result); 152112ed2d3SChris Wilson return ERR_PTR(err); 153112ed2d3SChris Wilson } 154112ed2d3SChris Wilson 155112ed2d3SChris Wilson static u32 156112ed2d3SChris Wilson get_whitelist_reg(const struct intel_engine_cs *engine, unsigned int i) 157112ed2d3SChris Wilson { 158112ed2d3SChris Wilson i915_reg_t reg = i < engine->whitelist.count ? 159112ed2d3SChris Wilson engine->whitelist.list[i].reg : 160112ed2d3SChris Wilson RING_NOPID(engine->mmio_base); 161112ed2d3SChris Wilson 162112ed2d3SChris Wilson return i915_mmio_reg_offset(reg); 163112ed2d3SChris Wilson } 164112ed2d3SChris Wilson 165112ed2d3SChris Wilson static void 166112ed2d3SChris Wilson print_results(const struct intel_engine_cs *engine, const u32 *results) 167112ed2d3SChris Wilson { 168112ed2d3SChris Wilson unsigned int i; 169112ed2d3SChris Wilson 170112ed2d3SChris Wilson for (i = 0; i < RING_MAX_NONPRIV_SLOTS; i++) { 171112ed2d3SChris Wilson u32 expected = get_whitelist_reg(engine, i); 172112ed2d3SChris Wilson u32 actual = results[i]; 173112ed2d3SChris Wilson 174112ed2d3SChris Wilson pr_info("RING_NONPRIV[%d]: expected 0x%08x, found 0x%08x\n", 175112ed2d3SChris Wilson i, expected, actual); 176112ed2d3SChris Wilson } 177112ed2d3SChris Wilson } 178112ed2d3SChris Wilson 179112ed2d3SChris Wilson static int check_whitelist(struct i915_gem_context *ctx, 180112ed2d3SChris Wilson struct intel_engine_cs *engine) 181112ed2d3SChris Wilson { 182112ed2d3SChris Wilson struct drm_i915_gem_object *results; 183cb823ed9SChris Wilson struct intel_wedge_me wedge; 184112ed2d3SChris Wilson u32 *vaddr; 185112ed2d3SChris Wilson int err; 186112ed2d3SChris Wilson int i; 187112ed2d3SChris Wilson 188112ed2d3SChris Wilson results = read_nonprivs(ctx, engine); 189112ed2d3SChris Wilson if (IS_ERR(results)) 190112ed2d3SChris Wilson return PTR_ERR(results); 191112ed2d3SChris Wilson 192112ed2d3SChris Wilson err = 0; 1936951e589SChris Wilson i915_gem_object_lock(results); 194cb823ed9SChris Wilson intel_wedge_on_timeout(&wedge, &ctx->i915->gt, HZ / 5) /* safety net! */ 195112ed2d3SChris Wilson err = i915_gem_object_set_to_cpu_domain(results, false); 1966951e589SChris Wilson i915_gem_object_unlock(results); 197cb823ed9SChris Wilson if (intel_gt_is_wedged(&ctx->i915->gt)) 198112ed2d3SChris Wilson err = -EIO; 199112ed2d3SChris Wilson if (err) 200112ed2d3SChris Wilson goto out_put; 201112ed2d3SChris Wilson 202112ed2d3SChris Wilson vaddr = i915_gem_object_pin_map(results, I915_MAP_WB); 203112ed2d3SChris Wilson if (IS_ERR(vaddr)) { 204112ed2d3SChris Wilson err = PTR_ERR(vaddr); 205112ed2d3SChris Wilson goto out_put; 206112ed2d3SChris Wilson } 207112ed2d3SChris Wilson 208112ed2d3SChris Wilson for (i = 0; i < RING_MAX_NONPRIV_SLOTS; i++) { 209112ed2d3SChris Wilson u32 expected = get_whitelist_reg(engine, i); 210112ed2d3SChris Wilson u32 actual = vaddr[i]; 211112ed2d3SChris Wilson 212112ed2d3SChris Wilson if (expected != actual) { 213112ed2d3SChris Wilson print_results(engine, vaddr); 214112ed2d3SChris Wilson pr_err("Invalid RING_NONPRIV[%d], expected 0x%08x, found 0x%08x\n", 215112ed2d3SChris Wilson i, expected, actual); 216112ed2d3SChris Wilson 217112ed2d3SChris Wilson err = -EINVAL; 218112ed2d3SChris Wilson break; 219112ed2d3SChris Wilson } 220112ed2d3SChris Wilson } 221112ed2d3SChris Wilson 222112ed2d3SChris Wilson i915_gem_object_unpin_map(results); 223112ed2d3SChris Wilson out_put: 224112ed2d3SChris Wilson i915_gem_object_put(results); 225112ed2d3SChris Wilson return err; 226112ed2d3SChris Wilson } 227112ed2d3SChris Wilson 228112ed2d3SChris Wilson static int do_device_reset(struct intel_engine_cs *engine) 229112ed2d3SChris Wilson { 230cb823ed9SChris Wilson intel_gt_reset(engine->gt, engine->mask, "live_workarounds"); 231112ed2d3SChris Wilson return 0; 232112ed2d3SChris Wilson } 233112ed2d3SChris Wilson 234112ed2d3SChris Wilson static int do_engine_reset(struct intel_engine_cs *engine) 235112ed2d3SChris Wilson { 236cb823ed9SChris Wilson return intel_engine_reset(engine, "live_workarounds"); 237112ed2d3SChris Wilson } 238112ed2d3SChris Wilson 239112ed2d3SChris Wilson static int 240112ed2d3SChris Wilson switch_to_scratch_context(struct intel_engine_cs *engine, 241112ed2d3SChris Wilson struct igt_spinner *spin) 242112ed2d3SChris Wilson { 243112ed2d3SChris Wilson struct i915_gem_context *ctx; 244f277bc0cSChris Wilson struct intel_context *ce; 245112ed2d3SChris Wilson struct i915_request *rq; 246112ed2d3SChris Wilson intel_wakeref_t wakeref; 247112ed2d3SChris Wilson int err = 0; 248112ed2d3SChris Wilson 249112ed2d3SChris Wilson ctx = kernel_context(engine->i915); 250112ed2d3SChris Wilson if (IS_ERR(ctx)) 251112ed2d3SChris Wilson return PTR_ERR(ctx); 252112ed2d3SChris Wilson 253112ed2d3SChris Wilson GEM_BUG_ON(i915_gem_context_is_bannable(ctx)); 254112ed2d3SChris Wilson 255f1c4d157SChris Wilson ce = i915_gem_context_get_engine(ctx, engine->legacy_idx); 256f277bc0cSChris Wilson GEM_BUG_ON(IS_ERR(ce)); 257f277bc0cSChris Wilson 258112ed2d3SChris Wilson rq = ERR_PTR(-ENODEV); 259c447ff7dSDaniele Ceraolo Spurio with_intel_runtime_pm(&engine->i915->runtime_pm, wakeref) 260f277bc0cSChris Wilson rq = igt_spinner_create_request(spin, ce, MI_NOOP); 261112ed2d3SChris Wilson 262f277bc0cSChris Wilson intel_context_put(ce); 263112ed2d3SChris Wilson kernel_context_close(ctx); 264112ed2d3SChris Wilson 265112ed2d3SChris Wilson if (IS_ERR(rq)) { 266112ed2d3SChris Wilson spin = NULL; 267112ed2d3SChris Wilson err = PTR_ERR(rq); 268112ed2d3SChris Wilson goto err; 269112ed2d3SChris Wilson } 270112ed2d3SChris Wilson 271112ed2d3SChris Wilson i915_request_add(rq); 272112ed2d3SChris Wilson 273112ed2d3SChris Wilson if (spin && !igt_wait_for_spinner(spin, rq)) { 274112ed2d3SChris Wilson pr_err("Spinner failed to start\n"); 275112ed2d3SChris Wilson err = -ETIMEDOUT; 276112ed2d3SChris Wilson } 277112ed2d3SChris Wilson 278112ed2d3SChris Wilson err: 279112ed2d3SChris Wilson if (err && spin) 280112ed2d3SChris Wilson igt_spinner_end(spin); 281112ed2d3SChris Wilson 282112ed2d3SChris Wilson return err; 283112ed2d3SChris Wilson } 284112ed2d3SChris Wilson 285112ed2d3SChris Wilson static int check_whitelist_across_reset(struct intel_engine_cs *engine, 286112ed2d3SChris Wilson int (*reset)(struct intel_engine_cs *), 287112ed2d3SChris Wilson const char *name) 288112ed2d3SChris Wilson { 289112ed2d3SChris Wilson struct drm_i915_private *i915 = engine->i915; 290cf3bd1a0SChris Wilson struct i915_gem_context *ctx, *tmp; 291112ed2d3SChris Wilson struct igt_spinner spin; 292112ed2d3SChris Wilson intel_wakeref_t wakeref; 293112ed2d3SChris Wilson int err; 294112ed2d3SChris Wilson 2953e1f0a51SJohn Harrison pr_info("Checking %d whitelisted registers on %s (RING_NONPRIV) [%s]\n", 2963e1f0a51SJohn Harrison engine->whitelist.count, engine->name, name); 297112ed2d3SChris Wilson 298112ed2d3SChris Wilson ctx = kernel_context(i915); 299112ed2d3SChris Wilson if (IS_ERR(ctx)) 300112ed2d3SChris Wilson return PTR_ERR(ctx); 301112ed2d3SChris Wilson 302f277bc0cSChris Wilson err = igt_spinner_init(&spin, engine->gt); 303cf3bd1a0SChris Wilson if (err) 304cf3bd1a0SChris Wilson goto out_ctx; 305cf3bd1a0SChris Wilson 306112ed2d3SChris Wilson err = check_whitelist(ctx, engine); 307112ed2d3SChris Wilson if (err) { 308112ed2d3SChris Wilson pr_err("Invalid whitelist *before* %s reset!\n", name); 309cf3bd1a0SChris Wilson goto out_spin; 310112ed2d3SChris Wilson } 311112ed2d3SChris Wilson 312112ed2d3SChris Wilson err = switch_to_scratch_context(engine, &spin); 313112ed2d3SChris Wilson if (err) 314cf3bd1a0SChris Wilson goto out_spin; 315112ed2d3SChris Wilson 316c447ff7dSDaniele Ceraolo Spurio with_intel_runtime_pm(&i915->runtime_pm, wakeref) 317112ed2d3SChris Wilson err = reset(engine); 318112ed2d3SChris Wilson 319112ed2d3SChris Wilson igt_spinner_end(&spin); 320112ed2d3SChris Wilson 321112ed2d3SChris Wilson if (err) { 322112ed2d3SChris Wilson pr_err("%s reset failed\n", name); 323cf3bd1a0SChris Wilson goto out_spin; 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); 330cf3bd1a0SChris Wilson goto out_spin; 331112ed2d3SChris Wilson } 332112ed2d3SChris Wilson 333cf3bd1a0SChris Wilson tmp = kernel_context(i915); 334cf3bd1a0SChris Wilson if (IS_ERR(tmp)) { 335cf3bd1a0SChris Wilson err = PTR_ERR(tmp); 336cf3bd1a0SChris Wilson goto out_spin; 337cf3bd1a0SChris Wilson } 338112ed2d3SChris Wilson kernel_context_close(ctx); 339cf3bd1a0SChris Wilson ctx = tmp; 340112ed2d3SChris Wilson 341112ed2d3SChris Wilson err = check_whitelist(ctx, engine); 342112ed2d3SChris Wilson if (err) { 343112ed2d3SChris Wilson pr_err("Invalid whitelist *after* %s reset in fresh context!\n", 344112ed2d3SChris Wilson name); 345cf3bd1a0SChris Wilson goto out_spin; 346112ed2d3SChris Wilson } 347112ed2d3SChris Wilson 348cf3bd1a0SChris Wilson out_spin: 349cf3bd1a0SChris Wilson igt_spinner_fini(&spin); 350cf3bd1a0SChris Wilson out_ctx: 351112ed2d3SChris Wilson kernel_context_close(ctx); 352112ed2d3SChris Wilson return err; 353112ed2d3SChris Wilson } 354112ed2d3SChris Wilson 355112ed2d3SChris Wilson static struct i915_vma *create_batch(struct i915_gem_context *ctx) 356112ed2d3SChris Wilson { 357112ed2d3SChris Wilson struct drm_i915_gem_object *obj; 358112ed2d3SChris Wilson struct i915_vma *vma; 359112ed2d3SChris Wilson int err; 360112ed2d3SChris Wilson 361112ed2d3SChris Wilson obj = i915_gem_object_create_internal(ctx->i915, 16 * PAGE_SIZE); 362112ed2d3SChris Wilson if (IS_ERR(obj)) 363112ed2d3SChris Wilson return ERR_CAST(obj); 364112ed2d3SChris Wilson 365e568ac38SChris Wilson vma = i915_vma_instance(obj, ctx->vm, NULL); 366112ed2d3SChris Wilson if (IS_ERR(vma)) { 367112ed2d3SChris Wilson err = PTR_ERR(vma); 368112ed2d3SChris Wilson goto err_obj; 369112ed2d3SChris Wilson } 370112ed2d3SChris Wilson 371112ed2d3SChris Wilson err = i915_vma_pin(vma, 0, 0, PIN_USER); 372112ed2d3SChris Wilson if (err) 373112ed2d3SChris Wilson goto err_obj; 374112ed2d3SChris Wilson 375112ed2d3SChris Wilson return vma; 376112ed2d3SChris Wilson 377112ed2d3SChris Wilson err_obj: 378112ed2d3SChris Wilson i915_gem_object_put(obj); 379112ed2d3SChris Wilson return ERR_PTR(err); 380112ed2d3SChris Wilson } 381112ed2d3SChris Wilson 382112ed2d3SChris Wilson static u32 reg_write(u32 old, u32 new, u32 rsvd) 383112ed2d3SChris Wilson { 384112ed2d3SChris Wilson if (rsvd == 0x0000ffff) { 385112ed2d3SChris Wilson old &= ~(new >> 16); 386112ed2d3SChris Wilson old |= new & (new >> 16); 387112ed2d3SChris Wilson } else { 388112ed2d3SChris Wilson old &= ~rsvd; 389112ed2d3SChris Wilson old |= new & rsvd; 390112ed2d3SChris Wilson } 391112ed2d3SChris Wilson 392112ed2d3SChris Wilson return old; 393112ed2d3SChris Wilson } 394112ed2d3SChris Wilson 395112ed2d3SChris Wilson static bool wo_register(struct intel_engine_cs *engine, u32 reg) 396112ed2d3SChris Wilson { 397112ed2d3SChris Wilson enum intel_platform platform = INTEL_INFO(engine->i915)->platform; 398112ed2d3SChris Wilson int i; 399112ed2d3SChris Wilson 4001e2b7f49SJohn Harrison if ((reg & RING_FORCE_TO_NONPRIV_ACCESS_MASK) == 4011e2b7f49SJohn Harrison RING_FORCE_TO_NONPRIV_ACCESS_WR) 4021e2b7f49SJohn Harrison return true; 4031e2b7f49SJohn Harrison 404112ed2d3SChris Wilson for (i = 0; i < ARRAY_SIZE(wo_registers); i++) { 405112ed2d3SChris Wilson if (wo_registers[i].platform == platform && 406112ed2d3SChris Wilson wo_registers[i].reg == reg) 407112ed2d3SChris Wilson return true; 408112ed2d3SChris Wilson } 409112ed2d3SChris Wilson 410112ed2d3SChris Wilson return false; 411112ed2d3SChris Wilson } 412112ed2d3SChris Wilson 413767662bcSRobert M. Fosha static bool ro_register(u32 reg) 414767662bcSRobert M. Fosha { 4151e2b7f49SJohn Harrison if ((reg & RING_FORCE_TO_NONPRIV_ACCESS_MASK) == 4161e2b7f49SJohn Harrison RING_FORCE_TO_NONPRIV_ACCESS_RD) 417767662bcSRobert M. Fosha return true; 418767662bcSRobert M. Fosha 419767662bcSRobert M. Fosha return false; 420767662bcSRobert M. Fosha } 421767662bcSRobert M. Fosha 422767662bcSRobert M. Fosha static int whitelist_writable_count(struct intel_engine_cs *engine) 423767662bcSRobert M. Fosha { 424767662bcSRobert M. Fosha int count = engine->whitelist.count; 425767662bcSRobert M. Fosha int i; 426767662bcSRobert M. Fosha 427767662bcSRobert M. Fosha for (i = 0; i < engine->whitelist.count; i++) { 428767662bcSRobert M. Fosha u32 reg = i915_mmio_reg_offset(engine->whitelist.list[i].reg); 429767662bcSRobert M. Fosha 430767662bcSRobert M. Fosha if (ro_register(reg)) 431767662bcSRobert M. Fosha count--; 432767662bcSRobert M. Fosha } 433767662bcSRobert M. Fosha 434767662bcSRobert M. Fosha return count; 435767662bcSRobert M. Fosha } 436767662bcSRobert M. Fosha 437112ed2d3SChris Wilson static int check_dirty_whitelist(struct i915_gem_context *ctx, 438112ed2d3SChris Wilson struct intel_engine_cs *engine) 439112ed2d3SChris Wilson { 440112ed2d3SChris Wilson const u32 values[] = { 441112ed2d3SChris Wilson 0x00000000, 442112ed2d3SChris Wilson 0x01010101, 443112ed2d3SChris Wilson 0x10100101, 444112ed2d3SChris Wilson 0x03030303, 445112ed2d3SChris Wilson 0x30300303, 446112ed2d3SChris Wilson 0x05050505, 447112ed2d3SChris Wilson 0x50500505, 448112ed2d3SChris Wilson 0x0f0f0f0f, 449112ed2d3SChris Wilson 0xf00ff00f, 450112ed2d3SChris Wilson 0x10101010, 451112ed2d3SChris Wilson 0xf0f01010, 452112ed2d3SChris Wilson 0x30303030, 453112ed2d3SChris Wilson 0xa0a03030, 454112ed2d3SChris Wilson 0x50505050, 455112ed2d3SChris Wilson 0xc0c05050, 456112ed2d3SChris Wilson 0xf0f0f0f0, 457112ed2d3SChris Wilson 0x11111111, 458112ed2d3SChris Wilson 0x33333333, 459112ed2d3SChris Wilson 0x55555555, 460112ed2d3SChris Wilson 0x0000ffff, 461112ed2d3SChris Wilson 0x00ff00ff, 462112ed2d3SChris Wilson 0xff0000ff, 463112ed2d3SChris Wilson 0xffff00ff, 464112ed2d3SChris Wilson 0xffffffff, 465112ed2d3SChris Wilson }; 466112ed2d3SChris Wilson struct i915_vma *scratch; 467112ed2d3SChris Wilson struct i915_vma *batch; 468112ed2d3SChris Wilson int err = 0, i, v; 469112ed2d3SChris Wilson u32 *cs, *results; 470112ed2d3SChris Wilson 471e568ac38SChris Wilson scratch = create_scratch(ctx->vm, 2 * ARRAY_SIZE(values) + 1); 472112ed2d3SChris Wilson if (IS_ERR(scratch)) 473112ed2d3SChris Wilson return PTR_ERR(scratch); 474112ed2d3SChris Wilson 475112ed2d3SChris Wilson batch = create_batch(ctx); 476112ed2d3SChris Wilson if (IS_ERR(batch)) { 477112ed2d3SChris Wilson err = PTR_ERR(batch); 478112ed2d3SChris Wilson goto out_scratch; 479112ed2d3SChris Wilson } 480112ed2d3SChris Wilson 481112ed2d3SChris Wilson for (i = 0; i < engine->whitelist.count; i++) { 482112ed2d3SChris Wilson u32 reg = i915_mmio_reg_offset(engine->whitelist.list[i].reg); 483112ed2d3SChris Wilson u64 addr = scratch->node.start; 484112ed2d3SChris Wilson struct i915_request *rq; 485112ed2d3SChris Wilson u32 srm, lrm, rsvd; 486112ed2d3SChris Wilson u32 expect; 487112ed2d3SChris Wilson int idx; 488aee20aaeSJohn Harrison bool ro_reg; 489112ed2d3SChris Wilson 490112ed2d3SChris Wilson if (wo_register(engine, reg)) 491112ed2d3SChris Wilson continue; 492112ed2d3SChris Wilson 493aee20aaeSJohn Harrison ro_reg = ro_register(reg); 494767662bcSRobert M. Fosha 495112ed2d3SChris Wilson srm = MI_STORE_REGISTER_MEM; 496112ed2d3SChris Wilson lrm = MI_LOAD_REGISTER_MEM; 497112ed2d3SChris Wilson if (INTEL_GEN(ctx->i915) >= 8) 498112ed2d3SChris Wilson lrm++, srm++; 499112ed2d3SChris Wilson 500112ed2d3SChris Wilson pr_debug("%s: Writing garbage to %x\n", 501112ed2d3SChris Wilson engine->name, reg); 502112ed2d3SChris Wilson 503112ed2d3SChris Wilson cs = i915_gem_object_pin_map(batch->obj, I915_MAP_WC); 504112ed2d3SChris Wilson if (IS_ERR(cs)) { 505112ed2d3SChris Wilson err = PTR_ERR(cs); 506112ed2d3SChris Wilson goto out_batch; 507112ed2d3SChris Wilson } 508112ed2d3SChris Wilson 509112ed2d3SChris Wilson /* SRM original */ 510112ed2d3SChris Wilson *cs++ = srm; 511112ed2d3SChris Wilson *cs++ = reg; 512112ed2d3SChris Wilson *cs++ = lower_32_bits(addr); 513112ed2d3SChris Wilson *cs++ = upper_32_bits(addr); 514112ed2d3SChris Wilson 515112ed2d3SChris Wilson idx = 1; 516112ed2d3SChris Wilson for (v = 0; v < ARRAY_SIZE(values); v++) { 517112ed2d3SChris Wilson /* LRI garbage */ 518112ed2d3SChris Wilson *cs++ = MI_LOAD_REGISTER_IMM(1); 519112ed2d3SChris Wilson *cs++ = reg; 520112ed2d3SChris Wilson *cs++ = values[v]; 521112ed2d3SChris Wilson 522112ed2d3SChris Wilson /* SRM result */ 523112ed2d3SChris Wilson *cs++ = srm; 524112ed2d3SChris Wilson *cs++ = reg; 525112ed2d3SChris Wilson *cs++ = lower_32_bits(addr + sizeof(u32) * idx); 526112ed2d3SChris Wilson *cs++ = upper_32_bits(addr + sizeof(u32) * idx); 527112ed2d3SChris Wilson idx++; 528112ed2d3SChris Wilson } 529112ed2d3SChris Wilson for (v = 0; v < ARRAY_SIZE(values); v++) { 530112ed2d3SChris Wilson /* LRI garbage */ 531112ed2d3SChris Wilson *cs++ = MI_LOAD_REGISTER_IMM(1); 532112ed2d3SChris Wilson *cs++ = reg; 533112ed2d3SChris Wilson *cs++ = ~values[v]; 534112ed2d3SChris Wilson 535112ed2d3SChris Wilson /* SRM result */ 536112ed2d3SChris Wilson *cs++ = srm; 537112ed2d3SChris Wilson *cs++ = reg; 538112ed2d3SChris Wilson *cs++ = lower_32_bits(addr + sizeof(u32) * idx); 539112ed2d3SChris Wilson *cs++ = upper_32_bits(addr + sizeof(u32) * idx); 540112ed2d3SChris Wilson idx++; 541112ed2d3SChris Wilson } 542112ed2d3SChris Wilson GEM_BUG_ON(idx * sizeof(u32) > scratch->size); 543112ed2d3SChris Wilson 544112ed2d3SChris Wilson /* LRM original -- don't leave garbage in the context! */ 545112ed2d3SChris Wilson *cs++ = lrm; 546112ed2d3SChris Wilson *cs++ = reg; 547112ed2d3SChris Wilson *cs++ = lower_32_bits(addr); 548112ed2d3SChris Wilson *cs++ = upper_32_bits(addr); 549112ed2d3SChris Wilson 550112ed2d3SChris Wilson *cs++ = MI_BATCH_BUFFER_END; 551112ed2d3SChris Wilson 552112ed2d3SChris Wilson i915_gem_object_flush_map(batch->obj); 553112ed2d3SChris Wilson i915_gem_object_unpin_map(batch->obj); 554baea429dSTvrtko Ursulin intel_gt_chipset_flush(engine->gt); 555112ed2d3SChris Wilson 55646472b3eSChris Wilson rq = igt_request_alloc(ctx, engine); 557112ed2d3SChris Wilson if (IS_ERR(rq)) { 558112ed2d3SChris Wilson err = PTR_ERR(rq); 559112ed2d3SChris Wilson goto out_batch; 560112ed2d3SChris Wilson } 561112ed2d3SChris Wilson 562112ed2d3SChris Wilson if (engine->emit_init_breadcrumb) { /* Be nice if we hang */ 563112ed2d3SChris Wilson err = engine->emit_init_breadcrumb(rq); 564112ed2d3SChris Wilson if (err) 565112ed2d3SChris Wilson goto err_request; 566112ed2d3SChris Wilson } 567112ed2d3SChris Wilson 568112ed2d3SChris Wilson err = engine->emit_bb_start(rq, 569112ed2d3SChris Wilson batch->node.start, PAGE_SIZE, 570112ed2d3SChris Wilson 0); 571112ed2d3SChris Wilson if (err) 572112ed2d3SChris Wilson goto err_request; 573112ed2d3SChris Wilson 574112ed2d3SChris Wilson err_request: 575112ed2d3SChris Wilson i915_request_add(rq); 576112ed2d3SChris Wilson if (err) 577112ed2d3SChris Wilson goto out_batch; 578112ed2d3SChris Wilson 5792f530945SChris Wilson if (i915_request_wait(rq, 0, HZ / 5) < 0) { 580112ed2d3SChris Wilson pr_err("%s: Futzing %x timedout; cancelling test\n", 581112ed2d3SChris Wilson engine->name, reg); 582cb823ed9SChris Wilson intel_gt_set_wedged(&ctx->i915->gt); 583112ed2d3SChris Wilson err = -EIO; 584112ed2d3SChris Wilson goto out_batch; 585112ed2d3SChris Wilson } 586112ed2d3SChris Wilson 587112ed2d3SChris Wilson results = i915_gem_object_pin_map(scratch->obj, I915_MAP_WB); 588112ed2d3SChris Wilson if (IS_ERR(results)) { 589112ed2d3SChris Wilson err = PTR_ERR(results); 590112ed2d3SChris Wilson goto out_batch; 591112ed2d3SChris Wilson } 592112ed2d3SChris Wilson 593112ed2d3SChris Wilson GEM_BUG_ON(values[ARRAY_SIZE(values) - 1] != 0xffffffff); 594aee20aaeSJohn Harrison if (!ro_reg) { 595aee20aaeSJohn Harrison /* detect write masking */ 596aee20aaeSJohn Harrison rsvd = results[ARRAY_SIZE(values)]; 597112ed2d3SChris Wilson if (!rsvd) { 598112ed2d3SChris Wilson pr_err("%s: Unable to write to whitelisted register %x\n", 599112ed2d3SChris Wilson engine->name, reg); 600112ed2d3SChris Wilson err = -EINVAL; 601112ed2d3SChris Wilson goto out_unpin; 602112ed2d3SChris Wilson } 603aee20aaeSJohn Harrison } 604112ed2d3SChris Wilson 605112ed2d3SChris Wilson expect = results[0]; 606112ed2d3SChris Wilson idx = 1; 607112ed2d3SChris Wilson for (v = 0; v < ARRAY_SIZE(values); v++) { 608aee20aaeSJohn Harrison if (ro_reg) 609aee20aaeSJohn Harrison expect = results[0]; 610aee20aaeSJohn Harrison else 611112ed2d3SChris Wilson expect = reg_write(expect, values[v], rsvd); 612aee20aaeSJohn Harrison 613112ed2d3SChris Wilson if (results[idx] != expect) 614112ed2d3SChris Wilson err++; 615112ed2d3SChris Wilson idx++; 616112ed2d3SChris Wilson } 617112ed2d3SChris Wilson for (v = 0; v < ARRAY_SIZE(values); v++) { 618aee20aaeSJohn Harrison if (ro_reg) 619aee20aaeSJohn Harrison expect = results[0]; 620aee20aaeSJohn Harrison else 621112ed2d3SChris Wilson expect = reg_write(expect, ~values[v], rsvd); 622aee20aaeSJohn Harrison 623112ed2d3SChris Wilson if (results[idx] != expect) 624112ed2d3SChris Wilson err++; 625112ed2d3SChris Wilson idx++; 626112ed2d3SChris Wilson } 627112ed2d3SChris Wilson if (err) { 628112ed2d3SChris Wilson pr_err("%s: %d mismatch between values written to whitelisted register [%x], and values read back!\n", 629112ed2d3SChris Wilson engine->name, err, reg); 630112ed2d3SChris Wilson 631aee20aaeSJohn Harrison if (ro_reg) 632aee20aaeSJohn Harrison pr_info("%s: Whitelisted read-only register: %x, original value %08x\n", 633aee20aaeSJohn Harrison engine->name, reg, results[0]); 634aee20aaeSJohn Harrison else 635112ed2d3SChris Wilson pr_info("%s: Whitelisted register: %x, original value %08x, rsvd %08x\n", 636112ed2d3SChris Wilson engine->name, reg, results[0], rsvd); 637112ed2d3SChris Wilson 638112ed2d3SChris Wilson expect = results[0]; 639112ed2d3SChris Wilson idx = 1; 640112ed2d3SChris Wilson for (v = 0; v < ARRAY_SIZE(values); v++) { 641112ed2d3SChris Wilson u32 w = values[v]; 642112ed2d3SChris Wilson 643aee20aaeSJohn Harrison if (ro_reg) 644aee20aaeSJohn Harrison expect = results[0]; 645aee20aaeSJohn Harrison else 646112ed2d3SChris Wilson expect = reg_write(expect, w, rsvd); 647112ed2d3SChris Wilson pr_info("Wrote %08x, read %08x, expect %08x\n", 648112ed2d3SChris Wilson w, results[idx], expect); 649112ed2d3SChris Wilson idx++; 650112ed2d3SChris Wilson } 651112ed2d3SChris Wilson for (v = 0; v < ARRAY_SIZE(values); v++) { 652112ed2d3SChris Wilson u32 w = ~values[v]; 653112ed2d3SChris Wilson 654aee20aaeSJohn Harrison if (ro_reg) 655aee20aaeSJohn Harrison expect = results[0]; 656aee20aaeSJohn Harrison else 657112ed2d3SChris Wilson expect = reg_write(expect, w, rsvd); 658112ed2d3SChris Wilson pr_info("Wrote %08x, read %08x, expect %08x\n", 659112ed2d3SChris Wilson w, results[idx], expect); 660112ed2d3SChris Wilson idx++; 661112ed2d3SChris Wilson } 662112ed2d3SChris Wilson 663112ed2d3SChris Wilson err = -EINVAL; 664112ed2d3SChris Wilson } 665112ed2d3SChris Wilson out_unpin: 666112ed2d3SChris Wilson i915_gem_object_unpin_map(scratch->obj); 667112ed2d3SChris Wilson if (err) 668112ed2d3SChris Wilson break; 669112ed2d3SChris Wilson } 670112ed2d3SChris Wilson 671112ed2d3SChris Wilson if (igt_flush_test(ctx->i915, I915_WAIT_LOCKED)) 672112ed2d3SChris Wilson err = -EIO; 673112ed2d3SChris Wilson out_batch: 674112ed2d3SChris Wilson i915_vma_unpin_and_release(&batch, 0); 675112ed2d3SChris Wilson out_scratch: 676112ed2d3SChris Wilson i915_vma_unpin_and_release(&scratch, 0); 677112ed2d3SChris Wilson return err; 678112ed2d3SChris Wilson } 679112ed2d3SChris Wilson 680112ed2d3SChris Wilson static int live_dirty_whitelist(void *arg) 681112ed2d3SChris Wilson { 682112ed2d3SChris Wilson struct drm_i915_private *i915 = arg; 683112ed2d3SChris Wilson struct intel_engine_cs *engine; 684112ed2d3SChris Wilson struct i915_gem_context *ctx; 685112ed2d3SChris Wilson enum intel_engine_id id; 686112ed2d3SChris Wilson intel_wakeref_t wakeref; 687112ed2d3SChris Wilson struct drm_file *file; 688112ed2d3SChris Wilson int err = 0; 689112ed2d3SChris Wilson 690112ed2d3SChris Wilson /* Can the user write to the whitelisted registers? */ 691112ed2d3SChris Wilson 692112ed2d3SChris Wilson if (INTEL_GEN(i915) < 7) /* minimum requirement for LRI, SRM, LRM */ 693112ed2d3SChris Wilson return 0; 694112ed2d3SChris Wilson 695d858d569SDaniele Ceraolo Spurio wakeref = intel_runtime_pm_get(&i915->runtime_pm); 696112ed2d3SChris Wilson 697112ed2d3SChris Wilson mutex_unlock(&i915->drm.struct_mutex); 698112ed2d3SChris Wilson file = mock_file(i915); 699112ed2d3SChris Wilson mutex_lock(&i915->drm.struct_mutex); 700112ed2d3SChris Wilson if (IS_ERR(file)) { 701112ed2d3SChris Wilson err = PTR_ERR(file); 702112ed2d3SChris Wilson goto out_rpm; 703112ed2d3SChris Wilson } 704112ed2d3SChris Wilson 705112ed2d3SChris Wilson ctx = live_context(i915, file); 706112ed2d3SChris Wilson if (IS_ERR(ctx)) { 707112ed2d3SChris Wilson err = PTR_ERR(ctx); 708112ed2d3SChris Wilson goto out_file; 709112ed2d3SChris Wilson } 710112ed2d3SChris Wilson 711112ed2d3SChris Wilson for_each_engine(engine, i915, id) { 712112ed2d3SChris Wilson if (engine->whitelist.count == 0) 713112ed2d3SChris Wilson continue; 714112ed2d3SChris Wilson 715112ed2d3SChris Wilson err = check_dirty_whitelist(ctx, engine); 716112ed2d3SChris Wilson if (err) 717112ed2d3SChris Wilson goto out_file; 718112ed2d3SChris Wilson } 719112ed2d3SChris Wilson 720112ed2d3SChris Wilson out_file: 721112ed2d3SChris Wilson mutex_unlock(&i915->drm.struct_mutex); 722112ed2d3SChris Wilson mock_file_free(i915, file); 723112ed2d3SChris Wilson mutex_lock(&i915->drm.struct_mutex); 724112ed2d3SChris Wilson out_rpm: 725d858d569SDaniele Ceraolo Spurio intel_runtime_pm_put(&i915->runtime_pm, wakeref); 726112ed2d3SChris Wilson return err; 727112ed2d3SChris Wilson } 728112ed2d3SChris Wilson 729112ed2d3SChris Wilson static int live_reset_whitelist(void *arg) 730112ed2d3SChris Wilson { 731112ed2d3SChris Wilson struct drm_i915_private *i915 = arg; 732112ed2d3SChris Wilson struct intel_engine_cs *engine = i915->engine[RCS0]; 733112ed2d3SChris Wilson int err = 0; 734112ed2d3SChris Wilson 735112ed2d3SChris Wilson /* If we reset the gpu, we should not lose the RING_NONPRIV */ 736112ed2d3SChris Wilson 737112ed2d3SChris Wilson if (!engine || engine->whitelist.count == 0) 738112ed2d3SChris Wilson return 0; 739112ed2d3SChris Wilson 740cb823ed9SChris Wilson igt_global_reset_lock(&i915->gt); 741112ed2d3SChris Wilson 742112ed2d3SChris Wilson if (intel_has_reset_engine(i915)) { 743112ed2d3SChris Wilson err = check_whitelist_across_reset(engine, 744112ed2d3SChris Wilson do_engine_reset, 745112ed2d3SChris Wilson "engine"); 746112ed2d3SChris Wilson if (err) 747112ed2d3SChris Wilson goto out; 748112ed2d3SChris Wilson } 749112ed2d3SChris Wilson 750112ed2d3SChris Wilson if (intel_has_gpu_reset(i915)) { 751112ed2d3SChris Wilson err = check_whitelist_across_reset(engine, 752112ed2d3SChris Wilson do_device_reset, 753112ed2d3SChris Wilson "device"); 754112ed2d3SChris Wilson if (err) 755112ed2d3SChris Wilson goto out; 756112ed2d3SChris Wilson } 757112ed2d3SChris Wilson 758112ed2d3SChris Wilson out: 759cb823ed9SChris Wilson igt_global_reset_unlock(&i915->gt); 760112ed2d3SChris Wilson return err; 761112ed2d3SChris Wilson } 762112ed2d3SChris Wilson 763112ed2d3SChris Wilson static int read_whitelisted_registers(struct i915_gem_context *ctx, 764112ed2d3SChris Wilson struct intel_engine_cs *engine, 765112ed2d3SChris Wilson struct i915_vma *results) 766112ed2d3SChris Wilson { 767112ed2d3SChris Wilson struct i915_request *rq; 768112ed2d3SChris Wilson int i, err = 0; 769112ed2d3SChris Wilson u32 srm, *cs; 770112ed2d3SChris Wilson 77146472b3eSChris Wilson rq = igt_request_alloc(ctx, engine); 772112ed2d3SChris Wilson if (IS_ERR(rq)) 773112ed2d3SChris Wilson return PTR_ERR(rq); 774112ed2d3SChris Wilson 775112ed2d3SChris Wilson srm = MI_STORE_REGISTER_MEM; 776112ed2d3SChris Wilson if (INTEL_GEN(ctx->i915) >= 8) 777112ed2d3SChris Wilson srm++; 778112ed2d3SChris Wilson 779112ed2d3SChris Wilson cs = intel_ring_begin(rq, 4 * engine->whitelist.count); 780112ed2d3SChris Wilson if (IS_ERR(cs)) { 781112ed2d3SChris Wilson err = PTR_ERR(cs); 782112ed2d3SChris Wilson goto err_req; 783112ed2d3SChris Wilson } 784112ed2d3SChris Wilson 785112ed2d3SChris Wilson for (i = 0; i < engine->whitelist.count; i++) { 786112ed2d3SChris Wilson u64 offset = results->node.start + sizeof(u32) * i; 787767662bcSRobert M. Fosha u32 reg = i915_mmio_reg_offset(engine->whitelist.list[i].reg); 788767662bcSRobert M. Fosha 7891e2b7f49SJohn Harrison /* Clear access permission field */ 7901e2b7f49SJohn Harrison reg &= ~RING_FORCE_TO_NONPRIV_ACCESS_MASK; 791112ed2d3SChris Wilson 792112ed2d3SChris Wilson *cs++ = srm; 793767662bcSRobert M. Fosha *cs++ = reg; 794112ed2d3SChris Wilson *cs++ = lower_32_bits(offset); 795112ed2d3SChris Wilson *cs++ = upper_32_bits(offset); 796112ed2d3SChris Wilson } 797112ed2d3SChris Wilson intel_ring_advance(rq, cs); 798112ed2d3SChris Wilson 799112ed2d3SChris Wilson err_req: 800112ed2d3SChris Wilson i915_request_add(rq); 801112ed2d3SChris Wilson 8022f530945SChris Wilson if (i915_request_wait(rq, 0, HZ / 5) < 0) 803112ed2d3SChris Wilson err = -EIO; 804112ed2d3SChris Wilson 805112ed2d3SChris Wilson return err; 806112ed2d3SChris Wilson } 807112ed2d3SChris Wilson 808112ed2d3SChris Wilson static int scrub_whitelisted_registers(struct i915_gem_context *ctx, 809112ed2d3SChris Wilson struct intel_engine_cs *engine) 810112ed2d3SChris Wilson { 811112ed2d3SChris Wilson struct i915_request *rq; 812112ed2d3SChris Wilson struct i915_vma *batch; 813112ed2d3SChris Wilson int i, err = 0; 814112ed2d3SChris Wilson u32 *cs; 815112ed2d3SChris Wilson 816112ed2d3SChris Wilson batch = create_batch(ctx); 817112ed2d3SChris Wilson if (IS_ERR(batch)) 818112ed2d3SChris Wilson return PTR_ERR(batch); 819112ed2d3SChris Wilson 820112ed2d3SChris Wilson cs = i915_gem_object_pin_map(batch->obj, I915_MAP_WC); 821112ed2d3SChris Wilson if (IS_ERR(cs)) { 822112ed2d3SChris Wilson err = PTR_ERR(cs); 823112ed2d3SChris Wilson goto err_batch; 824112ed2d3SChris Wilson } 825112ed2d3SChris Wilson 826767662bcSRobert M. Fosha *cs++ = MI_LOAD_REGISTER_IMM(whitelist_writable_count(engine)); 827112ed2d3SChris Wilson for (i = 0; i < engine->whitelist.count; i++) { 828767662bcSRobert M. Fosha u32 reg = i915_mmio_reg_offset(engine->whitelist.list[i].reg); 829767662bcSRobert M. Fosha 830767662bcSRobert M. Fosha if (ro_register(reg)) 831767662bcSRobert M. Fosha continue; 832767662bcSRobert M. Fosha 833767662bcSRobert M. Fosha *cs++ = reg; 834112ed2d3SChris Wilson *cs++ = 0xffffffff; 835112ed2d3SChris Wilson } 836112ed2d3SChris Wilson *cs++ = MI_BATCH_BUFFER_END; 837112ed2d3SChris Wilson 838112ed2d3SChris Wilson i915_gem_object_flush_map(batch->obj); 839baea429dSTvrtko Ursulin intel_gt_chipset_flush(engine->gt); 840112ed2d3SChris Wilson 84146472b3eSChris Wilson rq = igt_request_alloc(ctx, engine); 842112ed2d3SChris Wilson if (IS_ERR(rq)) { 843112ed2d3SChris Wilson err = PTR_ERR(rq); 844112ed2d3SChris Wilson goto err_unpin; 845112ed2d3SChris Wilson } 846112ed2d3SChris Wilson 847112ed2d3SChris Wilson if (engine->emit_init_breadcrumb) { /* Be nice if we hang */ 848112ed2d3SChris Wilson err = engine->emit_init_breadcrumb(rq); 849112ed2d3SChris Wilson if (err) 850112ed2d3SChris Wilson goto err_request; 851112ed2d3SChris Wilson } 852112ed2d3SChris Wilson 853112ed2d3SChris Wilson /* Perform the writes from an unprivileged "user" batch */ 854112ed2d3SChris Wilson err = engine->emit_bb_start(rq, batch->node.start, 0, 0); 855112ed2d3SChris Wilson 856112ed2d3SChris Wilson err_request: 857112ed2d3SChris Wilson i915_request_add(rq); 8582f530945SChris Wilson if (i915_request_wait(rq, 0, HZ / 5) < 0) 859112ed2d3SChris Wilson err = -EIO; 860112ed2d3SChris Wilson 861112ed2d3SChris Wilson err_unpin: 862112ed2d3SChris Wilson i915_gem_object_unpin_map(batch->obj); 863112ed2d3SChris Wilson err_batch: 864112ed2d3SChris Wilson i915_vma_unpin_and_release(&batch, 0); 865112ed2d3SChris Wilson return err; 866112ed2d3SChris Wilson } 867112ed2d3SChris Wilson 868112ed2d3SChris Wilson struct regmask { 869112ed2d3SChris Wilson i915_reg_t reg; 870112ed2d3SChris Wilson unsigned long gen_mask; 871112ed2d3SChris Wilson }; 872112ed2d3SChris Wilson 873112ed2d3SChris Wilson static bool find_reg(struct drm_i915_private *i915, 874112ed2d3SChris Wilson i915_reg_t reg, 875112ed2d3SChris Wilson const struct regmask *tbl, 876112ed2d3SChris Wilson unsigned long count) 877112ed2d3SChris Wilson { 878112ed2d3SChris Wilson u32 offset = i915_mmio_reg_offset(reg); 879112ed2d3SChris Wilson 880112ed2d3SChris Wilson while (count--) { 881112ed2d3SChris Wilson if (INTEL_INFO(i915)->gen_mask & tbl->gen_mask && 882112ed2d3SChris Wilson i915_mmio_reg_offset(tbl->reg) == offset) 883112ed2d3SChris Wilson return true; 884112ed2d3SChris Wilson tbl++; 885112ed2d3SChris Wilson } 886112ed2d3SChris Wilson 887112ed2d3SChris Wilson return false; 888112ed2d3SChris Wilson } 889112ed2d3SChris Wilson 890112ed2d3SChris Wilson static bool pardon_reg(struct drm_i915_private *i915, i915_reg_t reg) 891112ed2d3SChris Wilson { 892112ed2d3SChris Wilson /* Alas, we must pardon some whitelists. Mistakes already made */ 893112ed2d3SChris Wilson static const struct regmask pardon[] = { 894112ed2d3SChris Wilson { GEN9_CTX_PREEMPT_REG, INTEL_GEN_MASK(9, 9) }, 895112ed2d3SChris Wilson { GEN8_L3SQCREG4, INTEL_GEN_MASK(9, 9) }, 896112ed2d3SChris Wilson }; 897112ed2d3SChris Wilson 898112ed2d3SChris Wilson return find_reg(i915, reg, pardon, ARRAY_SIZE(pardon)); 899112ed2d3SChris Wilson } 900112ed2d3SChris Wilson 901112ed2d3SChris Wilson static bool result_eq(struct intel_engine_cs *engine, 902112ed2d3SChris Wilson u32 a, u32 b, i915_reg_t reg) 903112ed2d3SChris Wilson { 904112ed2d3SChris Wilson if (a != b && !pardon_reg(engine->i915, reg)) { 905112ed2d3SChris Wilson pr_err("Whitelisted register 0x%4x not context saved: A=%08x, B=%08x\n", 906112ed2d3SChris Wilson i915_mmio_reg_offset(reg), a, b); 907112ed2d3SChris Wilson return false; 908112ed2d3SChris Wilson } 909112ed2d3SChris Wilson 910112ed2d3SChris Wilson return true; 911112ed2d3SChris Wilson } 912112ed2d3SChris Wilson 913112ed2d3SChris Wilson static bool writeonly_reg(struct drm_i915_private *i915, i915_reg_t reg) 914112ed2d3SChris Wilson { 915112ed2d3SChris Wilson /* Some registers do not seem to behave and our writes unreadable */ 916112ed2d3SChris Wilson static const struct regmask wo[] = { 917112ed2d3SChris Wilson { GEN9_SLICE_COMMON_ECO_CHICKEN1, INTEL_GEN_MASK(9, 9) }, 918112ed2d3SChris Wilson }; 919112ed2d3SChris Wilson 920112ed2d3SChris Wilson return find_reg(i915, reg, wo, ARRAY_SIZE(wo)); 921112ed2d3SChris Wilson } 922112ed2d3SChris Wilson 923112ed2d3SChris Wilson static bool result_neq(struct intel_engine_cs *engine, 924112ed2d3SChris Wilson u32 a, u32 b, i915_reg_t reg) 925112ed2d3SChris Wilson { 926112ed2d3SChris Wilson if (a == b && !writeonly_reg(engine->i915, reg)) { 927112ed2d3SChris Wilson pr_err("Whitelist register 0x%4x:%08x was unwritable\n", 928112ed2d3SChris Wilson i915_mmio_reg_offset(reg), a); 929112ed2d3SChris Wilson return false; 930112ed2d3SChris Wilson } 931112ed2d3SChris Wilson 932112ed2d3SChris Wilson return true; 933112ed2d3SChris Wilson } 934112ed2d3SChris Wilson 935112ed2d3SChris Wilson static int 936112ed2d3SChris Wilson check_whitelisted_registers(struct intel_engine_cs *engine, 937112ed2d3SChris Wilson struct i915_vma *A, 938112ed2d3SChris Wilson struct i915_vma *B, 939112ed2d3SChris Wilson bool (*fn)(struct intel_engine_cs *engine, 940112ed2d3SChris Wilson u32 a, u32 b, 941112ed2d3SChris Wilson i915_reg_t reg)) 942112ed2d3SChris Wilson { 943112ed2d3SChris Wilson u32 *a, *b; 944112ed2d3SChris Wilson int i, err; 945112ed2d3SChris Wilson 946112ed2d3SChris Wilson a = i915_gem_object_pin_map(A->obj, I915_MAP_WB); 947112ed2d3SChris Wilson if (IS_ERR(a)) 948112ed2d3SChris Wilson return PTR_ERR(a); 949112ed2d3SChris Wilson 950112ed2d3SChris Wilson b = i915_gem_object_pin_map(B->obj, I915_MAP_WB); 951112ed2d3SChris Wilson if (IS_ERR(b)) { 952112ed2d3SChris Wilson err = PTR_ERR(b); 953112ed2d3SChris Wilson goto err_a; 954112ed2d3SChris Wilson } 955112ed2d3SChris Wilson 956112ed2d3SChris Wilson err = 0; 957112ed2d3SChris Wilson for (i = 0; i < engine->whitelist.count; i++) { 958361b6905SLionel Landwerlin const struct i915_wa *wa = &engine->whitelist.list[i]; 959361b6905SLionel Landwerlin 9601e2b7f49SJohn Harrison if (i915_mmio_reg_offset(wa->reg) & 9611e2b7f49SJohn Harrison RING_FORCE_TO_NONPRIV_ACCESS_RD) 962361b6905SLionel Landwerlin continue; 963361b6905SLionel Landwerlin 964361b6905SLionel Landwerlin if (!fn(engine, a[i], b[i], wa->reg)) 965112ed2d3SChris Wilson err = -EINVAL; 966112ed2d3SChris Wilson } 967112ed2d3SChris Wilson 968112ed2d3SChris Wilson i915_gem_object_unpin_map(B->obj); 969112ed2d3SChris Wilson err_a: 970112ed2d3SChris Wilson i915_gem_object_unpin_map(A->obj); 971112ed2d3SChris Wilson return err; 972112ed2d3SChris Wilson } 973112ed2d3SChris Wilson 974112ed2d3SChris Wilson static int live_isolated_whitelist(void *arg) 975112ed2d3SChris Wilson { 976112ed2d3SChris Wilson struct drm_i915_private *i915 = arg; 977112ed2d3SChris Wilson struct { 978112ed2d3SChris Wilson struct i915_gem_context *ctx; 979112ed2d3SChris Wilson struct i915_vma *scratch[2]; 980112ed2d3SChris Wilson } client[2] = {}; 981112ed2d3SChris Wilson struct intel_engine_cs *engine; 982112ed2d3SChris Wilson enum intel_engine_id id; 983112ed2d3SChris Wilson int i, err = 0; 984112ed2d3SChris Wilson 985112ed2d3SChris Wilson /* 986112ed2d3SChris Wilson * Check that a write into a whitelist register works, but 987112ed2d3SChris Wilson * invisible to a second context. 988112ed2d3SChris Wilson */ 989112ed2d3SChris Wilson 990112ed2d3SChris Wilson if (!intel_engines_has_context_isolation(i915)) 991112ed2d3SChris Wilson return 0; 992112ed2d3SChris Wilson 993e568ac38SChris Wilson if (!i915->kernel_context->vm) 994112ed2d3SChris Wilson return 0; 995112ed2d3SChris Wilson 996112ed2d3SChris Wilson for (i = 0; i < ARRAY_SIZE(client); i++) { 997112ed2d3SChris Wilson struct i915_gem_context *c; 998112ed2d3SChris Wilson 999112ed2d3SChris Wilson c = kernel_context(i915); 1000112ed2d3SChris Wilson if (IS_ERR(c)) { 1001112ed2d3SChris Wilson err = PTR_ERR(c); 1002112ed2d3SChris Wilson goto err; 1003112ed2d3SChris Wilson } 1004112ed2d3SChris Wilson 1005e568ac38SChris Wilson client[i].scratch[0] = create_scratch(c->vm, 1024); 1006112ed2d3SChris Wilson if (IS_ERR(client[i].scratch[0])) { 1007112ed2d3SChris Wilson err = PTR_ERR(client[i].scratch[0]); 1008112ed2d3SChris Wilson kernel_context_close(c); 1009112ed2d3SChris Wilson goto err; 1010112ed2d3SChris Wilson } 1011112ed2d3SChris Wilson 1012e568ac38SChris Wilson client[i].scratch[1] = create_scratch(c->vm, 1024); 1013112ed2d3SChris Wilson if (IS_ERR(client[i].scratch[1])) { 1014112ed2d3SChris Wilson err = PTR_ERR(client[i].scratch[1]); 1015112ed2d3SChris Wilson i915_vma_unpin_and_release(&client[i].scratch[0], 0); 1016112ed2d3SChris Wilson kernel_context_close(c); 1017112ed2d3SChris Wilson goto err; 1018112ed2d3SChris Wilson } 1019112ed2d3SChris Wilson 1020112ed2d3SChris Wilson client[i].ctx = c; 1021112ed2d3SChris Wilson } 1022112ed2d3SChris Wilson 1023112ed2d3SChris Wilson for_each_engine(engine, i915, id) { 1024767662bcSRobert M. Fosha if (!whitelist_writable_count(engine)) 1025112ed2d3SChris Wilson continue; 1026112ed2d3SChris Wilson 1027112ed2d3SChris Wilson /* Read default values */ 1028112ed2d3SChris Wilson err = read_whitelisted_registers(client[0].ctx, engine, 1029112ed2d3SChris Wilson client[0].scratch[0]); 1030112ed2d3SChris Wilson if (err) 1031112ed2d3SChris Wilson goto err; 1032112ed2d3SChris Wilson 1033112ed2d3SChris Wilson /* Try to overwrite registers (should only affect ctx0) */ 1034112ed2d3SChris Wilson err = scrub_whitelisted_registers(client[0].ctx, engine); 1035112ed2d3SChris Wilson if (err) 1036112ed2d3SChris Wilson goto err; 1037112ed2d3SChris Wilson 1038112ed2d3SChris Wilson /* Read values from ctx1, we expect these to be defaults */ 1039112ed2d3SChris Wilson err = read_whitelisted_registers(client[1].ctx, engine, 1040112ed2d3SChris Wilson client[1].scratch[0]); 1041112ed2d3SChris Wilson if (err) 1042112ed2d3SChris Wilson goto err; 1043112ed2d3SChris Wilson 1044112ed2d3SChris Wilson /* Verify that both reads return the same default values */ 1045112ed2d3SChris Wilson err = check_whitelisted_registers(engine, 1046112ed2d3SChris Wilson client[0].scratch[0], 1047112ed2d3SChris Wilson client[1].scratch[0], 1048112ed2d3SChris Wilson result_eq); 1049112ed2d3SChris Wilson if (err) 1050112ed2d3SChris Wilson goto err; 1051112ed2d3SChris Wilson 1052112ed2d3SChris Wilson /* Read back the updated values in ctx0 */ 1053112ed2d3SChris Wilson err = read_whitelisted_registers(client[0].ctx, engine, 1054112ed2d3SChris Wilson client[0].scratch[1]); 1055112ed2d3SChris Wilson if (err) 1056112ed2d3SChris Wilson goto err; 1057112ed2d3SChris Wilson 1058112ed2d3SChris Wilson /* User should be granted privilege to overwhite regs */ 1059112ed2d3SChris Wilson err = check_whitelisted_registers(engine, 1060112ed2d3SChris Wilson client[0].scratch[0], 1061112ed2d3SChris Wilson client[0].scratch[1], 1062112ed2d3SChris Wilson result_neq); 1063112ed2d3SChris Wilson if (err) 1064112ed2d3SChris Wilson goto err; 1065112ed2d3SChris Wilson } 1066112ed2d3SChris Wilson 1067112ed2d3SChris Wilson err: 1068112ed2d3SChris Wilson for (i = 0; i < ARRAY_SIZE(client); i++) { 1069112ed2d3SChris Wilson if (!client[i].ctx) 1070112ed2d3SChris Wilson break; 1071112ed2d3SChris Wilson 1072112ed2d3SChris Wilson i915_vma_unpin_and_release(&client[i].scratch[1], 0); 1073112ed2d3SChris Wilson i915_vma_unpin_and_release(&client[i].scratch[0], 0); 1074112ed2d3SChris Wilson kernel_context_close(client[i].ctx); 1075112ed2d3SChris Wilson } 1076112ed2d3SChris Wilson 1077112ed2d3SChris Wilson if (igt_flush_test(i915, I915_WAIT_LOCKED)) 1078112ed2d3SChris Wilson err = -EIO; 1079112ed2d3SChris Wilson 1080112ed2d3SChris Wilson return err; 1081112ed2d3SChris Wilson } 1082112ed2d3SChris Wilson 1083fde93886STvrtko Ursulin static bool 1084fde93886STvrtko Ursulin verify_wa_lists(struct i915_gem_context *ctx, struct wa_lists *lists, 1085fde93886STvrtko Ursulin const char *str) 1086112ed2d3SChris Wilson { 1087fde93886STvrtko Ursulin struct drm_i915_private *i915 = ctx->i915; 1088fde93886STvrtko Ursulin struct i915_gem_engines_iter it; 1089fde93886STvrtko Ursulin struct intel_context *ce; 1090112ed2d3SChris Wilson bool ok = true; 1091112ed2d3SChris Wilson 1092112ed2d3SChris Wilson ok &= wa_list_verify(&i915->uncore, &lists->gt_wa_list, str); 1093112ed2d3SChris Wilson 1094f277bc0cSChris Wilson for_each_gem_engine(ce, i915_gem_context_engines(ctx), it) { 1095fde93886STvrtko Ursulin enum intel_engine_id id = ce->engine->id; 1096fde93886STvrtko Ursulin 1097fde93886STvrtko Ursulin ok &= engine_wa_list_verify(ce, 1098112ed2d3SChris Wilson &lists->engine[id].wa_list, 1099112ed2d3SChris Wilson str) == 0; 1100fde93886STvrtko Ursulin 1101fde93886STvrtko Ursulin ok &= engine_wa_list_verify(ce, 1102fde93886STvrtko Ursulin &lists->engine[id].ctx_wa_list, 1103fde93886STvrtko Ursulin str) == 0; 1104112ed2d3SChris Wilson } 1105112ed2d3SChris Wilson 1106112ed2d3SChris Wilson return ok; 1107112ed2d3SChris Wilson } 1108112ed2d3SChris Wilson 1109112ed2d3SChris Wilson static int 1110fde93886STvrtko Ursulin live_gpu_reset_workarounds(void *arg) 1111112ed2d3SChris Wilson { 1112112ed2d3SChris Wilson struct drm_i915_private *i915 = arg; 1113fde93886STvrtko Ursulin struct i915_gem_context *ctx; 1114112ed2d3SChris Wilson intel_wakeref_t wakeref; 1115112ed2d3SChris Wilson struct wa_lists lists; 1116112ed2d3SChris Wilson bool ok; 1117112ed2d3SChris Wilson 1118112ed2d3SChris Wilson if (!intel_has_gpu_reset(i915)) 1119112ed2d3SChris Wilson return 0; 1120112ed2d3SChris Wilson 1121fde93886STvrtko Ursulin ctx = kernel_context(i915); 1122fde93886STvrtko Ursulin if (IS_ERR(ctx)) 1123fde93886STvrtko Ursulin return PTR_ERR(ctx); 1124fde93886STvrtko Ursulin 1125f277bc0cSChris Wilson i915_gem_context_lock_engines(ctx); 1126f277bc0cSChris Wilson 1127112ed2d3SChris Wilson pr_info("Verifying after GPU reset...\n"); 1128112ed2d3SChris Wilson 1129cb823ed9SChris Wilson igt_global_reset_lock(&i915->gt); 1130d858d569SDaniele Ceraolo Spurio wakeref = intel_runtime_pm_get(&i915->runtime_pm); 1131112ed2d3SChris Wilson 1132112ed2d3SChris Wilson reference_lists_init(i915, &lists); 1133112ed2d3SChris Wilson 1134fde93886STvrtko Ursulin ok = verify_wa_lists(ctx, &lists, "before reset"); 1135112ed2d3SChris Wilson if (!ok) 1136112ed2d3SChris Wilson goto out; 1137112ed2d3SChris Wilson 1138cb823ed9SChris Wilson intel_gt_reset(&i915->gt, ALL_ENGINES, "live_workarounds"); 1139112ed2d3SChris Wilson 1140fde93886STvrtko Ursulin ok = verify_wa_lists(ctx, &lists, "after reset"); 1141112ed2d3SChris Wilson 1142112ed2d3SChris Wilson out: 1143f277bc0cSChris Wilson i915_gem_context_unlock_engines(ctx); 1144fde93886STvrtko Ursulin kernel_context_close(ctx); 1145112ed2d3SChris Wilson reference_lists_fini(i915, &lists); 1146d858d569SDaniele Ceraolo Spurio intel_runtime_pm_put(&i915->runtime_pm, wakeref); 1147cb823ed9SChris Wilson igt_global_reset_unlock(&i915->gt); 1148112ed2d3SChris Wilson 1149112ed2d3SChris Wilson return ok ? 0 : -ESRCH; 1150112ed2d3SChris Wilson } 1151112ed2d3SChris Wilson 1152112ed2d3SChris Wilson static int 1153fde93886STvrtko Ursulin live_engine_reset_workarounds(void *arg) 1154112ed2d3SChris Wilson { 1155112ed2d3SChris Wilson struct drm_i915_private *i915 = arg; 1156f277bc0cSChris Wilson struct i915_gem_engines_iter it; 1157112ed2d3SChris Wilson struct i915_gem_context *ctx; 1158f277bc0cSChris Wilson struct intel_context *ce; 1159112ed2d3SChris Wilson struct igt_spinner spin; 1160112ed2d3SChris Wilson struct i915_request *rq; 1161112ed2d3SChris Wilson intel_wakeref_t wakeref; 1162112ed2d3SChris Wilson struct wa_lists lists; 1163112ed2d3SChris Wilson int ret = 0; 1164112ed2d3SChris Wilson 1165112ed2d3SChris Wilson if (!intel_has_reset_engine(i915)) 1166112ed2d3SChris Wilson return 0; 1167112ed2d3SChris Wilson 1168112ed2d3SChris Wilson ctx = kernel_context(i915); 1169112ed2d3SChris Wilson if (IS_ERR(ctx)) 1170112ed2d3SChris Wilson return PTR_ERR(ctx); 1171112ed2d3SChris Wilson 1172cb823ed9SChris Wilson igt_global_reset_lock(&i915->gt); 1173d858d569SDaniele Ceraolo Spurio wakeref = intel_runtime_pm_get(&i915->runtime_pm); 1174112ed2d3SChris Wilson 1175112ed2d3SChris Wilson reference_lists_init(i915, &lists); 1176112ed2d3SChris Wilson 1177f277bc0cSChris Wilson for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) { 1178f277bc0cSChris Wilson struct intel_engine_cs *engine = ce->engine; 1179112ed2d3SChris Wilson bool ok; 1180112ed2d3SChris Wilson 1181112ed2d3SChris Wilson pr_info("Verifying after %s reset...\n", engine->name); 1182112ed2d3SChris Wilson 1183fde93886STvrtko Ursulin ok = verify_wa_lists(ctx, &lists, "before reset"); 1184112ed2d3SChris Wilson if (!ok) { 1185112ed2d3SChris Wilson ret = -ESRCH; 1186112ed2d3SChris Wilson goto err; 1187112ed2d3SChris Wilson } 1188112ed2d3SChris Wilson 1189cb823ed9SChris Wilson intel_engine_reset(engine, "live_workarounds"); 1190112ed2d3SChris Wilson 1191fde93886STvrtko Ursulin ok = verify_wa_lists(ctx, &lists, "after idle reset"); 1192112ed2d3SChris Wilson if (!ok) { 1193112ed2d3SChris Wilson ret = -ESRCH; 1194112ed2d3SChris Wilson goto err; 1195112ed2d3SChris Wilson } 1196112ed2d3SChris Wilson 1197f277bc0cSChris Wilson ret = igt_spinner_init(&spin, engine->gt); 1198112ed2d3SChris Wilson if (ret) 1199112ed2d3SChris Wilson goto err; 1200112ed2d3SChris Wilson 1201f277bc0cSChris Wilson rq = igt_spinner_create_request(&spin, ce, MI_NOOP); 1202112ed2d3SChris Wilson if (IS_ERR(rq)) { 1203112ed2d3SChris Wilson ret = PTR_ERR(rq); 1204112ed2d3SChris Wilson igt_spinner_fini(&spin); 1205112ed2d3SChris Wilson goto err; 1206112ed2d3SChris Wilson } 1207112ed2d3SChris Wilson 1208112ed2d3SChris Wilson i915_request_add(rq); 1209112ed2d3SChris Wilson 1210112ed2d3SChris Wilson if (!igt_wait_for_spinner(&spin, rq)) { 1211112ed2d3SChris Wilson pr_err("Spinner failed to start\n"); 1212112ed2d3SChris Wilson igt_spinner_fini(&spin); 1213112ed2d3SChris Wilson ret = -ETIMEDOUT; 1214112ed2d3SChris Wilson goto err; 1215112ed2d3SChris Wilson } 1216112ed2d3SChris Wilson 1217cb823ed9SChris Wilson intel_engine_reset(engine, "live_workarounds"); 1218112ed2d3SChris Wilson 1219112ed2d3SChris Wilson igt_spinner_end(&spin); 1220112ed2d3SChris Wilson igt_spinner_fini(&spin); 1221112ed2d3SChris Wilson 1222fde93886STvrtko Ursulin ok = verify_wa_lists(ctx, &lists, "after busy reset"); 1223112ed2d3SChris Wilson if (!ok) { 1224112ed2d3SChris Wilson ret = -ESRCH; 1225112ed2d3SChris Wilson goto err; 1226112ed2d3SChris Wilson } 1227112ed2d3SChris Wilson } 1228112ed2d3SChris Wilson err: 1229f277bc0cSChris Wilson i915_gem_context_unlock_engines(ctx); 1230112ed2d3SChris Wilson reference_lists_fini(i915, &lists); 1231d858d569SDaniele Ceraolo Spurio intel_runtime_pm_put(&i915->runtime_pm, wakeref); 1232cb823ed9SChris Wilson igt_global_reset_unlock(&i915->gt); 1233112ed2d3SChris Wilson kernel_context_close(ctx); 1234112ed2d3SChris Wilson 1235112ed2d3SChris Wilson igt_flush_test(i915, I915_WAIT_LOCKED); 1236112ed2d3SChris Wilson 1237112ed2d3SChris Wilson return ret; 1238112ed2d3SChris Wilson } 1239112ed2d3SChris Wilson 1240112ed2d3SChris Wilson int intel_workarounds_live_selftests(struct drm_i915_private *i915) 1241112ed2d3SChris Wilson { 1242112ed2d3SChris Wilson static const struct i915_subtest tests[] = { 1243112ed2d3SChris Wilson SUBTEST(live_dirty_whitelist), 1244112ed2d3SChris Wilson SUBTEST(live_reset_whitelist), 1245112ed2d3SChris Wilson SUBTEST(live_isolated_whitelist), 1246fde93886STvrtko Ursulin SUBTEST(live_gpu_reset_workarounds), 1247fde93886STvrtko Ursulin SUBTEST(live_engine_reset_workarounds), 1248112ed2d3SChris Wilson }; 1249112ed2d3SChris Wilson int err; 1250112ed2d3SChris Wilson 1251cb823ed9SChris Wilson if (intel_gt_is_wedged(&i915->gt)) 1252112ed2d3SChris Wilson return 0; 1253112ed2d3SChris Wilson 1254112ed2d3SChris Wilson mutex_lock(&i915->drm.struct_mutex); 1255112ed2d3SChris Wilson err = i915_subtests(tests, i915); 1256112ed2d3SChris Wilson mutex_unlock(&i915->drm.struct_mutex); 1257112ed2d3SChris Wilson 1258112ed2d3SChris Wilson return err; 1259112ed2d3SChris Wilson } 1260