summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/gt/selftest_rps.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2020-04-20 18:27:39 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2020-04-20 20:08:07 +0100
commite42a969e725c2ff93a0a66ca5d2c27d59310056e (patch)
treebc5ef309d40e26e76ee5b00e4e220f1775ade258 /drivers/gpu/drm/i915/gt/selftest_rps.c
parent6b36fc9442bbbb8d44a4d06315f189f88381809b (diff)
downloadlinux-e42a969e725c2ff93a0a66ca5d2c27d59310056e.tar.gz
linux-e42a969e725c2ff93a0a66ca5d2c27d59310056e.tar.bz2
linux-e42a969e725c2ff93a0a66ca5d2c27d59310056e.zip
drm/i915/selftests: Exercise dynamic reclocking with RPS
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
Diffstat (limited to 'drivers/gpu/drm/i915/gt/selftest_rps.c')
-rw-r--r--drivers/gpu/drm/i915/gt/selftest_rps.c112
1 files changed, 102 insertions, 10 deletions
diff --git a/drivers/gpu/drm/i915/gt/selftest_rps.c b/drivers/gpu/drm/i915/gt/selftest_rps.c
index 3f5b8cf928cc..d7cd673550ef 100644
--- a/drivers/gpu/drm/i915/gt/selftest_rps.c
+++ b/drivers/gpu/drm/i915/gt/selftest_rps.c
@@ -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;
+}