Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: MIT
0002 /*
0003  * Copyright © 2019 Intel Corporation
0004  */
0005 
0006 #include "intel_context.h"
0007 #include "intel_engine_pm.h"
0008 #include "intel_gpu_commands.h"
0009 #include "intel_gt_requests.h"
0010 #include "intel_ring.h"
0011 #include "selftest_rc6.h"
0012 
0013 #include "selftests/i915_random.h"
0014 #include "selftests/librapl.h"
0015 
0016 static u64 rc6_residency(struct intel_rc6 *rc6)
0017 {
0018     u64 result;
0019 
0020     /* XXX VLV_GT_MEDIA_RC6? */
0021 
0022     result = intel_rc6_residency_ns(rc6, GEN6_GT_GFX_RC6);
0023     if (HAS_RC6p(rc6_to_i915(rc6)))
0024         result += intel_rc6_residency_ns(rc6, GEN6_GT_GFX_RC6p);
0025     if (HAS_RC6pp(rc6_to_i915(rc6)))
0026         result += intel_rc6_residency_ns(rc6, GEN6_GT_GFX_RC6pp);
0027 
0028     return result;
0029 }
0030 
0031 int live_rc6_manual(void *arg)
0032 {
0033     struct intel_gt *gt = arg;
0034     struct intel_rc6 *rc6 = &gt->rc6;
0035     u64 rc0_power, rc6_power;
0036     intel_wakeref_t wakeref;
0037     bool has_power;
0038     ktime_t dt;
0039     u64 res[2];
0040     int err = 0;
0041 
0042     /*
0043      * Our claim is that we can "encourage" the GPU to enter rc6 at will.
0044      * Let's try it!
0045      */
0046 
0047     if (!rc6->enabled)
0048         return 0;
0049 
0050     /* bsw/byt use a PCU and decouple RC6 from our manual control */
0051     if (IS_VALLEYVIEW(gt->i915) || IS_CHERRYVIEW(gt->i915))
0052         return 0;
0053 
0054     has_power = librapl_supported(gt->i915);
0055     wakeref = intel_runtime_pm_get(gt->uncore->rpm);
0056 
0057     /* Force RC6 off for starters */
0058     __intel_rc6_disable(rc6);
0059     msleep(1); /* wakeup is not immediate, takes about 100us on icl */
0060 
0061     res[0] = rc6_residency(rc6);
0062 
0063     dt = ktime_get();
0064     rc0_power = librapl_energy_uJ();
0065     msleep(250);
0066     rc0_power = librapl_energy_uJ() - rc0_power;
0067     dt = ktime_sub(ktime_get(), dt);
0068     res[1] = rc6_residency(rc6);
0069     if ((res[1] - res[0]) >> 10) {
0070         pr_err("RC6 residency increased by %lldus while disabled for 250ms!\n",
0071                (res[1] - res[0]) >> 10);
0072         err = -EINVAL;
0073         goto out_unlock;
0074     }
0075 
0076     if (has_power) {
0077         rc0_power = div64_u64(NSEC_PER_SEC * rc0_power,
0078                       ktime_to_ns(dt));
0079         if (!rc0_power) {
0080             pr_err("No power measured while in RC0\n");
0081             err = -EINVAL;
0082             goto out_unlock;
0083         }
0084     }
0085 
0086     /* Manually enter RC6 */
0087     intel_rc6_park(rc6);
0088 
0089     res[0] = rc6_residency(rc6);
0090     intel_uncore_forcewake_flush(rc6_to_uncore(rc6), FORCEWAKE_ALL);
0091     dt = ktime_get();
0092     rc6_power = librapl_energy_uJ();
0093     msleep(100);
0094     rc6_power = librapl_energy_uJ() - rc6_power;
0095     dt = ktime_sub(ktime_get(), dt);
0096     res[1] = rc6_residency(rc6);
0097     if (res[1] == res[0]) {
0098         pr_err("Did not enter RC6! RC6_STATE=%08x, RC6_CONTROL=%08x, residency=%lld\n",
0099                intel_uncore_read_fw(gt->uncore, GEN6_RC_STATE),
0100                intel_uncore_read_fw(gt->uncore, GEN6_RC_CONTROL),
0101                res[0]);
0102         err = -EINVAL;
0103     }
0104 
0105     if (has_power) {
0106         rc6_power = div64_u64(NSEC_PER_SEC * rc6_power,
0107                       ktime_to_ns(dt));
0108         pr_info("GPU consumed %llduW in RC0 and %llduW in RC6\n",
0109             rc0_power, rc6_power);
0110         if (2 * rc6_power > rc0_power) {
0111             pr_err("GPU leaked energy while in RC6!\n");
0112             err = -EINVAL;
0113             goto out_unlock;
0114         }
0115     }
0116 
0117     /* Restore what should have been the original state! */
0118     intel_rc6_unpark(rc6);
0119 
0120 out_unlock:
0121     intel_runtime_pm_put(gt->uncore->rpm, wakeref);
0122     return err;
0123 }
0124 
0125 static const u32 *__live_rc6_ctx(struct intel_context *ce)
0126 {
0127     struct i915_request *rq;
0128     const u32 *result;
0129     u32 cmd;
0130     u32 *cs;
0131 
0132     rq = intel_context_create_request(ce);
0133     if (IS_ERR(rq))
0134         return ERR_CAST(rq);
0135 
0136     cs = intel_ring_begin(rq, 4);
0137     if (IS_ERR(cs)) {
0138         i915_request_add(rq);
0139         return cs;
0140     }
0141 
0142     cmd = MI_STORE_REGISTER_MEM | MI_USE_GGTT;
0143     if (GRAPHICS_VER(rq->engine->i915) >= 8)
0144         cmd++;
0145 
0146     *cs++ = cmd;
0147     *cs++ = i915_mmio_reg_offset(GEN8_RC6_CTX_INFO);
0148     *cs++ = ce->timeline->hwsp_offset + 8;
0149     *cs++ = 0;
0150     intel_ring_advance(rq, cs);
0151 
0152     result = rq->hwsp_seqno + 2;
0153     i915_request_add(rq);
0154 
0155     return result;
0156 }
0157 
0158 static struct intel_engine_cs **
0159 randomised_engines(struct intel_gt *gt,
0160            struct rnd_state *prng,
0161            unsigned int *count)
0162 {
0163     struct intel_engine_cs *engine, **engines;
0164     enum intel_engine_id id;
0165     int n;
0166 
0167     n = 0;
0168     for_each_engine(engine, gt, id)
0169         n++;
0170     if (!n)
0171         return NULL;
0172 
0173     engines = kmalloc_array(n, sizeof(*engines), GFP_KERNEL);
0174     if (!engines)
0175         return NULL;
0176 
0177     n = 0;
0178     for_each_engine(engine, gt, id)
0179         engines[n++] = engine;
0180 
0181     i915_prandom_shuffle(engines, sizeof(*engines), n, prng);
0182 
0183     *count = n;
0184     return engines;
0185 }
0186 
0187 int live_rc6_ctx_wa(void *arg)
0188 {
0189     struct intel_gt *gt = arg;
0190     struct intel_engine_cs **engines;
0191     unsigned int n, count;
0192     I915_RND_STATE(prng);
0193     int err = 0;
0194 
0195     /* A read of CTX_INFO upsets rc6. Poke the bear! */
0196     if (GRAPHICS_VER(gt->i915) < 8)
0197         return 0;
0198 
0199     engines = randomised_engines(gt, &prng, &count);
0200     if (!engines)
0201         return 0;
0202 
0203     for (n = 0; n < count; n++) {
0204         struct intel_engine_cs *engine = engines[n];
0205         int pass;
0206 
0207         for (pass = 0; pass < 2; pass++) {
0208             struct i915_gpu_error *error = &gt->i915->gpu_error;
0209             struct intel_context *ce;
0210             unsigned int resets =
0211                 i915_reset_engine_count(error, engine);
0212             const u32 *res;
0213 
0214             /* Use a sacrifical context */
0215             ce = intel_context_create(engine);
0216             if (IS_ERR(ce)) {
0217                 err = PTR_ERR(ce);
0218                 goto out;
0219             }
0220 
0221             intel_engine_pm_get(engine);
0222             res = __live_rc6_ctx(ce);
0223             intel_engine_pm_put(engine);
0224             intel_context_put(ce);
0225             if (IS_ERR(res)) {
0226                 err = PTR_ERR(res);
0227                 goto out;
0228             }
0229 
0230             if (intel_gt_wait_for_idle(gt, HZ / 5) == -ETIME) {
0231                 intel_gt_set_wedged(gt);
0232                 err = -ETIME;
0233                 goto out;
0234             }
0235 
0236             intel_gt_pm_wait_for_idle(gt);
0237             pr_debug("%s: CTX_INFO=%0x\n",
0238                  engine->name, READ_ONCE(*res));
0239 
0240             if (resets !=
0241                 i915_reset_engine_count(error, engine)) {
0242                 pr_err("%s: GPU reset required\n",
0243                        engine->name);
0244                 add_taint_for_CI(gt->i915, TAINT_WARN);
0245                 err = -EIO;
0246                 goto out;
0247             }
0248         }
0249     }
0250 
0251 out:
0252     kfree(engines);
0253     return err;
0254 }