0001
0002
0003
0004
0005
0006 #include "intel_engine_pm.h"
0007 #include "selftests/igt_flush_test.h"
0008
0009 static struct i915_vma *create_wally(struct intel_engine_cs *engine)
0010 {
0011 struct drm_i915_gem_object *obj;
0012 struct i915_vma *vma;
0013 u32 *cs;
0014 int err;
0015
0016 obj = i915_gem_object_create_internal(engine->i915, 4096);
0017 if (IS_ERR(obj))
0018 return ERR_CAST(obj);
0019
0020 vma = i915_vma_instance(obj, engine->gt->vm, NULL);
0021 if (IS_ERR(vma)) {
0022 i915_gem_object_put(obj);
0023 return vma;
0024 }
0025
0026 err = i915_vma_pin(vma, 0, 0, PIN_USER | PIN_HIGH);
0027 if (err) {
0028 i915_gem_object_put(obj);
0029 return ERR_PTR(err);
0030 }
0031
0032 err = i915_vma_sync(vma);
0033 if (err) {
0034 i915_gem_object_put(obj);
0035 return ERR_PTR(err);
0036 }
0037
0038 cs = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WC);
0039 if (IS_ERR(cs)) {
0040 i915_gem_object_put(obj);
0041 return ERR_CAST(cs);
0042 }
0043
0044 if (GRAPHICS_VER(engine->i915) >= 6) {
0045 *cs++ = MI_STORE_DWORD_IMM_GEN4;
0046 *cs++ = 0;
0047 } else if (GRAPHICS_VER(engine->i915) >= 4) {
0048 *cs++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
0049 *cs++ = 0;
0050 } else {
0051 *cs++ = MI_STORE_DWORD_IMM | MI_MEM_VIRTUAL;
0052 }
0053 *cs++ = vma->node.start + 4000;
0054 *cs++ = STACK_MAGIC;
0055
0056 *cs++ = MI_BATCH_BUFFER_END;
0057
0058 i915_gem_object_flush_map(obj);
0059 i915_gem_object_unpin_map(obj);
0060
0061 vma->private = intel_context_create(engine);
0062 if (IS_ERR(vma->private)) {
0063 vma = ERR_CAST(vma->private);
0064 i915_gem_object_put(obj);
0065 }
0066
0067 return vma;
0068 }
0069
0070 static int context_sync(struct intel_context *ce)
0071 {
0072 struct i915_request *rq;
0073 int err = 0;
0074
0075 rq = intel_context_create_request(ce);
0076 if (IS_ERR(rq))
0077 return PTR_ERR(rq);
0078
0079 i915_request_get(rq);
0080 i915_request_add(rq);
0081
0082 if (i915_request_wait(rq, 0, HZ / 5) < 0)
0083 err = -ETIME;
0084 i915_request_put(rq);
0085
0086 return err;
0087 }
0088
0089 static int new_context_sync(struct intel_engine_cs *engine)
0090 {
0091 struct intel_context *ce;
0092 int err;
0093
0094 ce = intel_context_create(engine);
0095 if (IS_ERR(ce))
0096 return PTR_ERR(ce);
0097
0098 err = context_sync(ce);
0099 intel_context_put(ce);
0100
0101 return err;
0102 }
0103
0104 static int mixed_contexts_sync(struct intel_engine_cs *engine, u32 *result)
0105 {
0106 int pass;
0107 int err;
0108
0109 for (pass = 0; pass < 2; pass++) {
0110 WRITE_ONCE(*result, 0);
0111 err = context_sync(engine->kernel_context);
0112 if (err || READ_ONCE(*result)) {
0113 if (!err) {
0114 pr_err("pass[%d] wa_bb emitted for the kernel context\n",
0115 pass);
0116 err = -EINVAL;
0117 }
0118 return err;
0119 }
0120
0121 WRITE_ONCE(*result, 0);
0122 err = new_context_sync(engine);
0123 if (READ_ONCE(*result) != STACK_MAGIC) {
0124 if (!err) {
0125 pr_err("pass[%d] wa_bb *NOT* emitted after the kernel context\n",
0126 pass);
0127 err = -EINVAL;
0128 }
0129 return err;
0130 }
0131
0132 WRITE_ONCE(*result, 0);
0133 err = new_context_sync(engine);
0134 if (READ_ONCE(*result) != STACK_MAGIC) {
0135 if (!err) {
0136 pr_err("pass[%d] wa_bb *NOT* emitted for the user context switch\n",
0137 pass);
0138 err = -EINVAL;
0139 }
0140 return err;
0141 }
0142 }
0143
0144 return 0;
0145 }
0146
0147 static int double_context_sync_00(struct intel_engine_cs *engine, u32 *result)
0148 {
0149 struct intel_context *ce;
0150 int err, i;
0151
0152 ce = intel_context_create(engine);
0153 if (IS_ERR(ce))
0154 return PTR_ERR(ce);
0155
0156 for (i = 0; i < 2; i++) {
0157 WRITE_ONCE(*result, 0);
0158 err = context_sync(ce);
0159 if (err)
0160 break;
0161 }
0162 intel_context_put(ce);
0163 if (err)
0164 return err;
0165
0166 if (READ_ONCE(*result)) {
0167 pr_err("wa_bb emitted between the same user context\n");
0168 return -EINVAL;
0169 }
0170
0171 return 0;
0172 }
0173
0174 static int kernel_context_sync_00(struct intel_engine_cs *engine, u32 *result)
0175 {
0176 struct intel_context *ce;
0177 int err, i;
0178
0179 ce = intel_context_create(engine);
0180 if (IS_ERR(ce))
0181 return PTR_ERR(ce);
0182
0183 for (i = 0; i < 2; i++) {
0184 WRITE_ONCE(*result, 0);
0185 err = context_sync(ce);
0186 if (err)
0187 break;
0188
0189 err = context_sync(engine->kernel_context);
0190 if (err)
0191 break;
0192 }
0193 intel_context_put(ce);
0194 if (err)
0195 return err;
0196
0197 if (READ_ONCE(*result)) {
0198 pr_err("wa_bb emitted between the same user context [with intervening kernel]\n");
0199 return -EINVAL;
0200 }
0201
0202 return 0;
0203 }
0204
0205 static int __live_ctx_switch_wa(struct intel_engine_cs *engine)
0206 {
0207 struct i915_vma *bb;
0208 u32 *result;
0209 int err;
0210
0211 bb = create_wally(engine);
0212 if (IS_ERR(bb))
0213 return PTR_ERR(bb);
0214
0215 result = i915_gem_object_pin_map_unlocked(bb->obj, I915_MAP_WC);
0216 if (IS_ERR(result)) {
0217 intel_context_put(bb->private);
0218 i915_vma_unpin_and_release(&bb, 0);
0219 return PTR_ERR(result);
0220 }
0221 result += 1000;
0222
0223 engine->wa_ctx.vma = bb;
0224
0225 err = mixed_contexts_sync(engine, result);
0226 if (err)
0227 goto out;
0228
0229 err = double_context_sync_00(engine, result);
0230 if (err)
0231 goto out;
0232
0233 err = kernel_context_sync_00(engine, result);
0234 if (err)
0235 goto out;
0236
0237 out:
0238 intel_context_put(engine->wa_ctx.vma->private);
0239 i915_vma_unpin_and_release(&engine->wa_ctx.vma, I915_VMA_RELEASE_MAP);
0240 return err;
0241 }
0242
0243 static int live_ctx_switch_wa(void *arg)
0244 {
0245 struct intel_gt *gt = arg;
0246 struct intel_engine_cs *engine;
0247 enum intel_engine_id id;
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262 for_each_engine(engine, gt, id) {
0263 struct i915_vma *saved_wa;
0264 int err;
0265
0266 if (!intel_engine_can_store_dword(engine))
0267 continue;
0268
0269 if (IS_GRAPHICS_VER(gt->i915, 4, 5))
0270 continue;
0271
0272 saved_wa = fetch_and_zero(&engine->wa_ctx.vma);
0273
0274 intel_engine_pm_get(engine);
0275 err = __live_ctx_switch_wa(engine);
0276 intel_engine_pm_put(engine);
0277 if (igt_flush_test(gt->i915))
0278 err = -EIO;
0279
0280 engine->wa_ctx.vma = saved_wa;
0281 if (err)
0282 return err;
0283 }
0284
0285 return 0;
0286 }
0287
0288 int intel_ring_submission_live_selftests(struct drm_i915_private *i915)
0289 {
0290 static const struct i915_subtest tests[] = {
0291 SUBTEST(live_ctx_switch_wa),
0292 };
0293
0294 if (to_gt(i915)->submission_method > INTEL_SUBMISSION_RING)
0295 return 0;
0296
0297 return intel_gt_live_subtests(tests, to_gt(i915));
0298 }