]> git.baikalelectronics.ru Git - kernel.git/commitdiff
drm/i915/selftests: Exercise dynamic reclocking with RPS
authorChris Wilson <chris@chris-wilson.co.uk>
Mon, 20 Apr 2020 17:27:39 +0000 (18:27 +0100)
committerChris Wilson <chris@chris-wilson.co.uk>
Mon, 20 Apr 2020 19:08:07 +0000 (20:08 +0100)
After having testing all the RPS controls individually, we need to take
a step back and check how our RPS worker integrates them to perform
dynamic GPU reclocking. So do that by submitting a spinner and wait and
see what happens.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200420172739.11620-6-chris@chris-wilson.co.uk
drivers/gpu/drm/i915/gt/selftest_gt_pm.c
drivers/gpu/drm/i915/gt/selftest_rps.c
drivers/gpu/drm/i915/gt/selftest_rps.h

index 9855e6f0ce7c65a0730e8cd4f0749ebd146673a4..e02fdec58826994eb3894484da24d889838f4df0 100644 (file)
@@ -58,6 +58,7 @@ int intel_gt_pm_live_selftests(struct drm_i915_private *i915)
                SUBTEST(live_rps_frequency_srm),
                SUBTEST(live_rps_power),
                SUBTEST(live_rps_interrupt),
+               SUBTEST(live_rps_dynamic),
                SUBTEST(live_gt_resume),
        };
 
index 3f5b8cf928ccaf37a1ad0a7a8d6783b187bbc76e..d7cd673550ef93d1536a95e31df35d8410607470 100644 (file)
@@ -110,24 +110,18 @@ create_spin_counter(struct intel_engine_cs *engine,
        return vma;
 }
 
-static u8 rps_set_check(struct intel_rps *rps, u8 freq)
+static u8 wait_for_freq(struct intel_rps *rps, u8 freq, int timeout_ms)
 {
        u8 history[64], i;
        unsigned long end;
        int sleep;
 
-       mutex_lock(&rps->lock);
-       GEM_BUG_ON(!rps->active);
-       intel_rps_set(rps, freq);
-       GEM_BUG_ON(rps->last_freq != freq);
-       mutex_unlock(&rps->lock);
-
        i = 0;
        memset(history, freq, sizeof(history));
        sleep = 20;
 
        /* The PCU does not change instantly, but drifts towards the goal? */
-       end = jiffies + msecs_to_jiffies(50);
+       end = jiffies + msecs_to_jiffies(timeout_ms);
        do {
                u8 act;
 
@@ -148,11 +142,22 @@ static u8 rps_set_check(struct intel_rps *rps, u8 freq)
 
                usleep_range(sleep, 2 * sleep);
                sleep *= 2;
-               if (sleep > 1000)
-                       sleep = 1000;
+               if (sleep > timeout_ms * 20)
+                       sleep = timeout_ms * 20;
        } while (1);
 }
 
+static u8 rps_set_check(struct intel_rps *rps, u8 freq)
+{
+       mutex_lock(&rps->lock);
+       GEM_BUG_ON(!rps->active);
+       intel_rps_set(rps, freq);
+       GEM_BUG_ON(rps->last_freq != freq);
+       mutex_unlock(&rps->lock);
+
+       return wait_for_freq(rps, freq, 50);
+}
+
 static void show_pstate_limits(struct intel_rps *rps)
 {
        struct drm_i915_private *i915 = rps_to_i915(rps);
@@ -949,3 +954,90 @@ int live_rps_power(void *arg)
 
        return err;
 }
+
+int live_rps_dynamic(void *arg)
+{
+       struct intel_gt *gt = arg;
+       struct intel_rps *rps = &gt->rps;
+       struct intel_engine_cs *engine;
+       enum intel_engine_id id;
+       struct igt_spinner spin;
+       int err = 0;
+
+       /*
+        * We've looked at the bascs, and have established that we
+        * can change the clock frequency and that the HW will generate
+        * interrupts based on load. Now we check how we integrate those
+        * moving parts into dynamic reclocking based on load.
+        */
+
+       if (!rps->enabled || rps->max_freq <= rps->min_freq)
+               return 0;
+
+       if (igt_spinner_init(&spin, gt))
+               return -ENOMEM;
+
+       for_each_engine(engine, gt, id) {
+               struct i915_request *rq;
+               struct {
+                       ktime_t dt;
+                       u8 freq;
+               } min, max;
+
+               if (!intel_engine_can_store_dword(engine))
+                       continue;
+
+               intel_gt_pm_wait_for_idle(gt);
+               GEM_BUG_ON(rps->active);
+               rps->cur_freq = rps->min_freq;
+
+               intel_engine_pm_get(engine);
+               intel_rc6_disable(&gt->rc6);
+               GEM_BUG_ON(rps->last_freq != rps->min_freq);
+
+               rq = igt_spinner_create_request(&spin,
+                                               engine->kernel_context,
+                                               MI_NOOP);
+               if (IS_ERR(rq)) {
+                       err = PTR_ERR(rq);
+                       goto err;
+               }
+
+               i915_request_add(rq);
+
+               max.dt = ktime_get();
+               max.freq = wait_for_freq(rps, rps->max_freq, 500);
+               max.dt = ktime_sub(ktime_get(), max.dt);
+
+               igt_spinner_end(&spin);
+
+               min.dt = ktime_get();
+               min.freq = wait_for_freq(rps, rps->min_freq, 2000);
+               min.dt = ktime_sub(ktime_get(), min.dt);
+
+               pr_info("%s: dynamically reclocked to %u:%uMHz while busy in %lluns, and %u:%uMHz while idle in %lluns\n",
+                       engine->name,
+                       max.freq, intel_gpu_freq(rps, max.freq),
+                       ktime_to_ns(max.dt),
+                       min.freq, intel_gpu_freq(rps, min.freq),
+                       ktime_to_ns(min.dt));
+               if (min.freq >= max.freq) {
+                       pr_err("%s: dynamic reclocking of spinner failed\n!",
+                              engine->name);
+                       err = -EINVAL;
+               }
+
+err:
+               intel_rc6_enable(&gt->rc6);
+               intel_engine_pm_put(engine);
+
+               if (igt_flush_test(gt->i915))
+                       err = -EIO;
+               if (err)
+                       break;
+       }
+
+       igt_spinner_fini(&spin);
+
+       return err;
+}
index 22e46c5341c59cbd8e43d46749d2c7cbb6047d84..76c4b19553e6c8738b6b7bf8cc4b94be236c1f1d 100644 (file)
@@ -9,7 +9,8 @@
 int live_rps_control(void *arg);
 int live_rps_frequency_cs(void *arg);
 int live_rps_frequency_srm(void *arg);
-int live_rps_interrupt(void *arg);
 int live_rps_power(void *arg);
+int live_rps_interrupt(void *arg);
+int live_rps_dynamic(void *arg);
 
 #endif /* SELFTEST_RPS_H */