diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2020-04-20 18:27:39 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2020-04-20 20:08:07 +0100 |
commit | e42a969e725c2ff93a0a66ca5d2c27d59310056e (patch) | |
tree | bc5ef309d40e26e76ee5b00e4e220f1775ade258 /drivers/gpu/drm/i915/gt/selftest_rps.c | |
parent | 6b36fc9442bbbb8d44a4d06315f189f88381809b (diff) | |
download | linux-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.c | 112 |
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 = >->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(>->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(>->rc6); + intel_engine_pm_put(engine); + + if (igt_flush_test(gt->i915)) + err = -EIO; + if (err) + break; + } + + igt_spinner_fini(&spin); + + return err; +} |