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
This commit is contained in:
parent
6b36fc9442
commit
e42a969e72
|
@ -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),
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue