1ba446f74SChris Wilson /* 2ba446f74SChris Wilson * SPDX-License-Identifier: MIT 3ba446f74SChris Wilson * 4ba446f74SChris Wilson * Copyright © 2019 Intel Corporation 5ba446f74SChris Wilson */ 6ba446f74SChris Wilson 7ba446f74SChris Wilson #include "intel_context.h" 8ba446f74SChris Wilson #include "intel_engine_pm.h" 9ba446f74SChris Wilson #include "intel_gt_requests.h" 10ba446f74SChris Wilson #include "intel_ring.h" 11ba446f74SChris Wilson #include "selftest_rc6.h" 12ba446f74SChris Wilson 13ba446f74SChris Wilson #include "selftests/i915_random.h" 14ba446f74SChris Wilson 15730eaeb5SChris Wilson int live_rc6_manual(void *arg) 16730eaeb5SChris Wilson { 17730eaeb5SChris Wilson struct intel_gt *gt = arg; 18730eaeb5SChris Wilson struct intel_rc6 *rc6 = >->rc6; 19730eaeb5SChris Wilson intel_wakeref_t wakeref; 20730eaeb5SChris Wilson u64 res[2]; 21730eaeb5SChris Wilson int err = 0; 22730eaeb5SChris Wilson 23730eaeb5SChris Wilson /* 24730eaeb5SChris Wilson * Our claim is that we can "encourage" the GPU to enter rc6 at will. 25730eaeb5SChris Wilson * Let's try it! 26730eaeb5SChris Wilson */ 27730eaeb5SChris Wilson 28730eaeb5SChris Wilson if (!rc6->enabled) 29730eaeb5SChris Wilson return 0; 30730eaeb5SChris Wilson 31730eaeb5SChris Wilson /* bsw/byt use a PCU and decouple RC6 from our manual control */ 32730eaeb5SChris Wilson if (IS_VALLEYVIEW(gt->i915) || IS_CHERRYVIEW(gt->i915)) 33730eaeb5SChris Wilson return 0; 34730eaeb5SChris Wilson 35730eaeb5SChris Wilson wakeref = intel_runtime_pm_get(gt->uncore->rpm); 36730eaeb5SChris Wilson 37730eaeb5SChris Wilson /* Force RC6 off for starters */ 38730eaeb5SChris Wilson __intel_rc6_disable(rc6); 39730eaeb5SChris Wilson msleep(1); /* wakeup is not immediate, takes about 100us on icl */ 40730eaeb5SChris Wilson 41730eaeb5SChris Wilson res[0] = intel_rc6_residency_ns(rc6, GEN6_GT_GFX_RC6); 42730eaeb5SChris Wilson msleep(250); 43730eaeb5SChris Wilson res[1] = intel_rc6_residency_ns(rc6, GEN6_GT_GFX_RC6); 44730eaeb5SChris Wilson if ((res[1] - res[0]) >> 10) { 45730eaeb5SChris Wilson pr_err("RC6 residency increased by %lldus while disabled for 250ms!\n", 46730eaeb5SChris Wilson (res[1] - res[0]) >> 10); 47730eaeb5SChris Wilson err = -EINVAL; 48730eaeb5SChris Wilson goto out_unlock; 49730eaeb5SChris Wilson } 50730eaeb5SChris Wilson 51730eaeb5SChris Wilson /* Manually enter RC6 */ 52730eaeb5SChris Wilson intel_rc6_park(rc6); 53730eaeb5SChris Wilson 54730eaeb5SChris Wilson res[0] = intel_rc6_residency_ns(rc6, GEN6_GT_GFX_RC6); 55730eaeb5SChris Wilson msleep(100); 56730eaeb5SChris Wilson res[1] = intel_rc6_residency_ns(rc6, GEN6_GT_GFX_RC6); 57730eaeb5SChris Wilson 58730eaeb5SChris Wilson if (res[1] == res[0]) { 59730eaeb5SChris Wilson pr_err("Did not enter RC6! RC6_STATE=%08x, RC6_CONTROL=%08x\n", 60730eaeb5SChris Wilson intel_uncore_read_fw(gt->uncore, GEN6_RC_STATE), 61730eaeb5SChris Wilson intel_uncore_read_fw(gt->uncore, GEN6_RC_CONTROL)); 62730eaeb5SChris Wilson err = -EINVAL; 63730eaeb5SChris Wilson } 64730eaeb5SChris Wilson 65730eaeb5SChris Wilson /* Restore what should have been the original state! */ 66730eaeb5SChris Wilson intel_rc6_unpark(rc6); 67730eaeb5SChris Wilson 68730eaeb5SChris Wilson out_unlock: 69730eaeb5SChris Wilson intel_runtime_pm_put(gt->uncore->rpm, wakeref); 70730eaeb5SChris Wilson return err; 71730eaeb5SChris Wilson } 72730eaeb5SChris Wilson 73ba446f74SChris Wilson static const u32 *__live_rc6_ctx(struct intel_context *ce) 74ba446f74SChris Wilson { 75ba446f74SChris Wilson struct i915_request *rq; 76ba446f74SChris Wilson const u32 *result; 77ba446f74SChris Wilson u32 cmd; 78ba446f74SChris Wilson u32 *cs; 79ba446f74SChris Wilson 80ba446f74SChris Wilson rq = intel_context_create_request(ce); 81ba446f74SChris Wilson if (IS_ERR(rq)) 82ba446f74SChris Wilson return ERR_CAST(rq); 83ba446f74SChris Wilson 84ba446f74SChris Wilson cs = intel_ring_begin(rq, 4); 85ba446f74SChris Wilson if (IS_ERR(cs)) { 86ba446f74SChris Wilson i915_request_add(rq); 87ba446f74SChris Wilson return cs; 88ba446f74SChris Wilson } 89ba446f74SChris Wilson 90ba446f74SChris Wilson cmd = MI_STORE_REGISTER_MEM | MI_USE_GGTT; 91ba446f74SChris Wilson if (INTEL_GEN(rq->i915) >= 8) 92ba446f74SChris Wilson cmd++; 93ba446f74SChris Wilson 94ba446f74SChris Wilson *cs++ = cmd; 95ba446f74SChris Wilson *cs++ = i915_mmio_reg_offset(GEN8_RC6_CTX_INFO); 96ba446f74SChris Wilson *cs++ = ce->timeline->hwsp_offset + 8; 97ba446f74SChris Wilson *cs++ = 0; 98ba446f74SChris Wilson intel_ring_advance(rq, cs); 99ba446f74SChris Wilson 100ba446f74SChris Wilson result = rq->hwsp_seqno + 2; 101ba446f74SChris Wilson i915_request_add(rq); 102ba446f74SChris Wilson 103ba446f74SChris Wilson return result; 104ba446f74SChris Wilson } 105ba446f74SChris Wilson 106ba446f74SChris Wilson static struct intel_engine_cs ** 107ba446f74SChris Wilson randomised_engines(struct intel_gt *gt, 108ba446f74SChris Wilson struct rnd_state *prng, 109ba446f74SChris Wilson unsigned int *count) 110ba446f74SChris Wilson { 111ba446f74SChris Wilson struct intel_engine_cs *engine, **engines; 112ba446f74SChris Wilson enum intel_engine_id id; 113ba446f74SChris Wilson int n; 114ba446f74SChris Wilson 115ba446f74SChris Wilson n = 0; 116ba446f74SChris Wilson for_each_engine(engine, gt, id) 117ba446f74SChris Wilson n++; 118ba446f74SChris Wilson if (!n) 119ba446f74SChris Wilson return NULL; 120ba446f74SChris Wilson 121ba446f74SChris Wilson engines = kmalloc_array(n, sizeof(*engines), GFP_KERNEL); 122ba446f74SChris Wilson if (!engines) 123ba446f74SChris Wilson return NULL; 124ba446f74SChris Wilson 125ba446f74SChris Wilson n = 0; 126ba446f74SChris Wilson for_each_engine(engine, gt, id) 127ba446f74SChris Wilson engines[n++] = engine; 128ba446f74SChris Wilson 129ba446f74SChris Wilson i915_prandom_shuffle(engines, sizeof(*engines), n, prng); 130ba446f74SChris Wilson 131ba446f74SChris Wilson *count = n; 132ba446f74SChris Wilson return engines; 133ba446f74SChris Wilson } 134ba446f74SChris Wilson 135ba446f74SChris Wilson int live_rc6_ctx_wa(void *arg) 136ba446f74SChris Wilson { 137ba446f74SChris Wilson struct intel_gt *gt = arg; 138ba446f74SChris Wilson struct intel_engine_cs **engines; 139ba446f74SChris Wilson unsigned int n, count; 140ba446f74SChris Wilson I915_RND_STATE(prng); 141ba446f74SChris Wilson int err = 0; 142ba446f74SChris Wilson 143ba446f74SChris Wilson /* A read of CTX_INFO upsets rc6. Poke the bear! */ 144ba446f74SChris Wilson if (INTEL_GEN(gt->i915) < 8) 145ba446f74SChris Wilson return 0; 146ba446f74SChris Wilson 147ba446f74SChris Wilson engines = randomised_engines(gt, &prng, &count); 148ba446f74SChris Wilson if (!engines) 149ba446f74SChris Wilson return 0; 150ba446f74SChris Wilson 151ba446f74SChris Wilson for (n = 0; n < count; n++) { 152ba446f74SChris Wilson struct intel_engine_cs *engine = engines[n]; 153ba446f74SChris Wilson int pass; 154ba446f74SChris Wilson 155ba446f74SChris Wilson for (pass = 0; pass < 2; pass++) { 156ba446f74SChris Wilson struct intel_context *ce; 157ba446f74SChris Wilson unsigned int resets = 158ba446f74SChris Wilson i915_reset_engine_count(>->i915->gpu_error, 159ba446f74SChris Wilson engine); 160ba446f74SChris Wilson const u32 *res; 161ba446f74SChris Wilson 162ba446f74SChris Wilson /* Use a sacrifical context */ 163e6ba7648SChris Wilson ce = intel_context_create(engine); 164ba446f74SChris Wilson if (IS_ERR(ce)) { 165ba446f74SChris Wilson err = PTR_ERR(ce); 166ba446f74SChris Wilson goto out; 167ba446f74SChris Wilson } 168ba446f74SChris Wilson 169ba446f74SChris Wilson intel_engine_pm_get(engine); 170ba446f74SChris Wilson res = __live_rc6_ctx(ce); 171ba446f74SChris Wilson intel_engine_pm_put(engine); 172ba446f74SChris Wilson intel_context_put(ce); 173ba446f74SChris Wilson if (IS_ERR(res)) { 174ba446f74SChris Wilson err = PTR_ERR(res); 175ba446f74SChris Wilson goto out; 176ba446f74SChris Wilson } 177ba446f74SChris Wilson 178ba446f74SChris Wilson if (intel_gt_wait_for_idle(gt, HZ / 5) == -ETIME) { 179ba446f74SChris Wilson intel_gt_set_wedged(gt); 180ba446f74SChris Wilson err = -ETIME; 181ba446f74SChris Wilson goto out; 182ba446f74SChris Wilson } 183ba446f74SChris Wilson 184ba446f74SChris Wilson intel_gt_pm_wait_for_idle(gt); 185ba446f74SChris Wilson pr_debug("%s: CTX_INFO=%0x\n", 186ba446f74SChris Wilson engine->name, READ_ONCE(*res)); 187ba446f74SChris Wilson 188ba446f74SChris Wilson if (resets != 189ba446f74SChris Wilson i915_reset_engine_count(>->i915->gpu_error, 190ba446f74SChris Wilson engine)) { 191ba446f74SChris Wilson pr_err("%s: GPU reset required\n", 192ba446f74SChris Wilson engine->name); 193ba446f74SChris Wilson add_taint_for_CI(TAINT_WARN); 194ba446f74SChris Wilson err = -EIO; 195ba446f74SChris Wilson goto out; 196ba446f74SChris Wilson } 197ba446f74SChris Wilson } 198ba446f74SChris Wilson } 199ba446f74SChris Wilson 200ba446f74SChris Wilson out: 201ba446f74SChris Wilson kfree(engines); 202ba446f74SChris Wilson return err; 203ba446f74SChris Wilson } 204