1 /* 2 * SPDX-License-Identifier: MIT 3 * 4 * Copyright © 2019 Intel Corporation 5 */ 6 7 #include "intel_context.h" 8 #include "intel_engine_pm.h" 9 #include "intel_gt_requests.h" 10 #include "intel_ring.h" 11 #include "selftest_rc6.h" 12 13 #include "selftests/i915_random.h" 14 15 int live_rc6_manual(void *arg) 16 { 17 struct intel_gt *gt = arg; 18 struct intel_rc6 *rc6 = >->rc6; 19 intel_wakeref_t wakeref; 20 u64 res[2]; 21 int err = 0; 22 23 /* 24 * Our claim is that we can "encourage" the GPU to enter rc6 at will. 25 * Let's try it! 26 */ 27 28 if (!rc6->enabled) 29 return 0; 30 31 /* bsw/byt use a PCU and decouple RC6 from our manual control */ 32 if (IS_VALLEYVIEW(gt->i915) || IS_CHERRYVIEW(gt->i915)) 33 return 0; 34 35 wakeref = intel_runtime_pm_get(gt->uncore->rpm); 36 37 /* Force RC6 off for starters */ 38 __intel_rc6_disable(rc6); 39 msleep(1); /* wakeup is not immediate, takes about 100us on icl */ 40 41 res[0] = intel_rc6_residency_ns(rc6, GEN6_GT_GFX_RC6); 42 msleep(250); 43 res[1] = intel_rc6_residency_ns(rc6, GEN6_GT_GFX_RC6); 44 if ((res[1] - res[0]) >> 10) { 45 pr_err("RC6 residency increased by %lldus while disabled for 250ms!\n", 46 (res[1] - res[0]) >> 10); 47 err = -EINVAL; 48 goto out_unlock; 49 } 50 51 /* Manually enter RC6 */ 52 intel_rc6_park(rc6); 53 54 res[0] = intel_rc6_residency_ns(rc6, GEN6_GT_GFX_RC6); 55 msleep(100); 56 res[1] = intel_rc6_residency_ns(rc6, GEN6_GT_GFX_RC6); 57 58 if (res[1] == res[0]) { 59 pr_err("Did not enter RC6! RC6_STATE=%08x, RC6_CONTROL=%08x, residency=%lld\n", 60 intel_uncore_read_fw(gt->uncore, GEN6_RC_STATE), 61 intel_uncore_read_fw(gt->uncore, GEN6_RC_CONTROL), 62 res[0]); 63 err = -EINVAL; 64 } 65 66 /* Restore what should have been the original state! */ 67 intel_rc6_unpark(rc6); 68 69 out_unlock: 70 intel_runtime_pm_put(gt->uncore->rpm, wakeref); 71 return err; 72 } 73 74 static const u32 *__live_rc6_ctx(struct intel_context *ce) 75 { 76 struct i915_request *rq; 77 const u32 *result; 78 u32 cmd; 79 u32 *cs; 80 81 rq = intel_context_create_request(ce); 82 if (IS_ERR(rq)) 83 return ERR_CAST(rq); 84 85 cs = intel_ring_begin(rq, 4); 86 if (IS_ERR(cs)) { 87 i915_request_add(rq); 88 return cs; 89 } 90 91 cmd = MI_STORE_REGISTER_MEM | MI_USE_GGTT; 92 if (INTEL_GEN(rq->i915) >= 8) 93 cmd++; 94 95 *cs++ = cmd; 96 *cs++ = i915_mmio_reg_offset(GEN8_RC6_CTX_INFO); 97 *cs++ = ce->timeline->hwsp_offset + 8; 98 *cs++ = 0; 99 intel_ring_advance(rq, cs); 100 101 result = rq->hwsp_seqno + 2; 102 i915_request_add(rq); 103 104 return result; 105 } 106 107 static struct intel_engine_cs ** 108 randomised_engines(struct intel_gt *gt, 109 struct rnd_state *prng, 110 unsigned int *count) 111 { 112 struct intel_engine_cs *engine, **engines; 113 enum intel_engine_id id; 114 int n; 115 116 n = 0; 117 for_each_engine(engine, gt, id) 118 n++; 119 if (!n) 120 return NULL; 121 122 engines = kmalloc_array(n, sizeof(*engines), GFP_KERNEL); 123 if (!engines) 124 return NULL; 125 126 n = 0; 127 for_each_engine(engine, gt, id) 128 engines[n++] = engine; 129 130 i915_prandom_shuffle(engines, sizeof(*engines), n, prng); 131 132 *count = n; 133 return engines; 134 } 135 136 int live_rc6_ctx_wa(void *arg) 137 { 138 struct intel_gt *gt = arg; 139 struct intel_engine_cs **engines; 140 unsigned int n, count; 141 I915_RND_STATE(prng); 142 int err = 0; 143 144 /* A read of CTX_INFO upsets rc6. Poke the bear! */ 145 if (INTEL_GEN(gt->i915) < 8) 146 return 0; 147 148 engines = randomised_engines(gt, &prng, &count); 149 if (!engines) 150 return 0; 151 152 for (n = 0; n < count; n++) { 153 struct intel_engine_cs *engine = engines[n]; 154 int pass; 155 156 for (pass = 0; pass < 2; pass++) { 157 struct intel_context *ce; 158 unsigned int resets = 159 i915_reset_engine_count(>->i915->gpu_error, 160 engine); 161 const u32 *res; 162 163 /* Use a sacrifical context */ 164 ce = intel_context_create(engine); 165 if (IS_ERR(ce)) { 166 err = PTR_ERR(ce); 167 goto out; 168 } 169 170 intel_engine_pm_get(engine); 171 res = __live_rc6_ctx(ce); 172 intel_engine_pm_put(engine); 173 intel_context_put(ce); 174 if (IS_ERR(res)) { 175 err = PTR_ERR(res); 176 goto out; 177 } 178 179 if (intel_gt_wait_for_idle(gt, HZ / 5) == -ETIME) { 180 intel_gt_set_wedged(gt); 181 err = -ETIME; 182 goto out; 183 } 184 185 intel_gt_pm_wait_for_idle(gt); 186 pr_debug("%s: CTX_INFO=%0x\n", 187 engine->name, READ_ONCE(*res)); 188 189 if (resets != 190 i915_reset_engine_count(>->i915->gpu_error, 191 engine)) { 192 pr_err("%s: GPU reset required\n", 193 engine->name); 194 add_taint_for_CI(TAINT_WARN); 195 err = -EIO; 196 goto out; 197 } 198 } 199 } 200 201 out: 202 kfree(engines); 203 return err; 204 } 205