Commit e42a969e authored by Chris Wilson's avatar Chris Wilson

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: default avatarChris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: default avatarMika Kuoppala <mika.kuoppala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200420172739.11620-6-chris@chris-wilson.co.uk
parent 6b36fc94
...@@ -58,6 +58,7 @@ int intel_gt_pm_live_selftests(struct drm_i915_private *i915) ...@@ -58,6 +58,7 @@ int intel_gt_pm_live_selftests(struct drm_i915_private *i915)
SUBTEST(live_rps_frequency_srm), SUBTEST(live_rps_frequency_srm),
SUBTEST(live_rps_power), SUBTEST(live_rps_power),
SUBTEST(live_rps_interrupt), SUBTEST(live_rps_interrupt),
SUBTEST(live_rps_dynamic),
SUBTEST(live_gt_resume), SUBTEST(live_gt_resume),
}; };
......
...@@ -110,24 +110,18 @@ create_spin_counter(struct intel_engine_cs *engine, ...@@ -110,24 +110,18 @@ create_spin_counter(struct intel_engine_cs *engine,
return vma; 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; u8 history[64], i;
unsigned long end; unsigned long end;
int sleep; 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; i = 0;
memset(history, freq, sizeof(history)); memset(history, freq, sizeof(history));
sleep = 20; sleep = 20;
/* The PCU does not change instantly, but drifts towards the goal? */ /* 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 { do {
u8 act; u8 act;
...@@ -148,11 +142,22 @@ static u8 rps_set_check(struct intel_rps *rps, u8 freq) ...@@ -148,11 +142,22 @@ static u8 rps_set_check(struct intel_rps *rps, u8 freq)
usleep_range(sleep, 2 * sleep); usleep_range(sleep, 2 * sleep);
sleep *= 2; sleep *= 2;
if (sleep > 1000) if (sleep > timeout_ms * 20)
sleep = 1000; sleep = timeout_ms * 20;
} while (1); } 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) static void show_pstate_limits(struct intel_rps *rps)
{ {
struct drm_i915_private *i915 = rps_to_i915(rps); struct drm_i915_private *i915 = rps_to_i915(rps);
...@@ -949,3 +954,90 @@ int live_rps_power(void *arg) ...@@ -949,3 +954,90 @@ int live_rps_power(void *arg)
return err; 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;
}
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
int live_rps_control(void *arg); int live_rps_control(void *arg);
int live_rps_frequency_cs(void *arg); int live_rps_frequency_cs(void *arg);
int live_rps_frequency_srm(void *arg); int live_rps_frequency_srm(void *arg);
int live_rps_interrupt(void *arg);
int live_rps_power(void *arg); int live_rps_power(void *arg);
int live_rps_interrupt(void *arg);
int live_rps_dynamic(void *arg);
#endif /* SELFTEST_RPS_H */ #endif /* SELFTEST_RPS_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment