Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: MIT
0002 /*
0003  * Copyright © 2020 Intel Corporation
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); /* dummy residuals */
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      * Exercise the inter-context wa batch.
0251      *
0252      * Between each user context we run a wa batch, and since it may
0253      * have implications for user visible state, we have to check that
0254      * we do actually execute it.
0255      *
0256      * The trick we use is to replace the normal wa batch with a custom
0257      * one that writes to a marker within it, and we can then look for
0258      * that marker to confirm if the batch was run when we expect it,
0259      * and equally important it was wasn't run when we don't!
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; /* MI_STORE_DWORD is privileged! */
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 }