[PATCH 1/3] rps-ring

Chris Wilson chris at chris-wilson.co.uk
Fri Jun 12 18:29:15 UTC 2020


---
 drivers/gpu/drm/i915/gt/intel_llc.c      |   3 +-
 drivers/gpu/drm/i915/gt/selftest_gt_pm.c |   1 +
 drivers/gpu/drm/i915/gt/selftest_llc.c   |  39 +++++++
 drivers/gpu/drm/i915/gt/selftest_llc.h   |   3 +
 drivers/gpu/drm/i915/gt/selftest_rps.c   | 134 +++++++++++++++++++++++
 drivers/gpu/drm/i915/gt/selftest_rps.h   |   1 +
 6 files changed, 179 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/intel_llc.c b/drivers/gpu/drm/i915/gt/intel_llc.c
index e3f637b3650e..a01b87c74e31 100644
--- a/drivers/gpu/drm/i915/gt/intel_llc.c
+++ b/drivers/gpu/drm/i915/gt/intel_llc.c
@@ -44,8 +44,7 @@ static unsigned int cpu_max_MHz(void)
 	return max_khz / 1000;
 }
 
-static bool get_ia_constants(struct intel_llc *llc,
-			     struct ia_constants *consts)
+static bool get_ia_constants(struct intel_llc *llc, struct ia_constants *consts)
 {
 	struct drm_i915_private *i915 = llc_to_gt(llc)->i915;
 	struct intel_rps *rps = &llc_to_gt(llc)->rps;
diff --git a/drivers/gpu/drm/i915/gt/selftest_gt_pm.c b/drivers/gpu/drm/i915/gt/selftest_gt_pm.c
index 6180a47c1b51..1038b5cf4fea 100644
--- a/drivers/gpu/drm/i915/gt/selftest_gt_pm.c
+++ b/drivers/gpu/drm/i915/gt/selftest_gt_pm.c
@@ -189,6 +189,7 @@ int intel_gt_pm_live_selftests(struct drm_i915_private *i915)
 		SUBTEST(live_rps_control),
 		SUBTEST(live_rps_frequency_cs),
 		SUBTEST(live_rps_frequency_srm),
+		SUBTEST(live_rps_frequency_ring),
 		SUBTEST(live_rps_power),
 		SUBTEST(live_rps_interrupt),
 		SUBTEST(live_rps_dynamic),
diff --git a/drivers/gpu/drm/i915/gt/selftest_llc.c b/drivers/gpu/drm/i915/gt/selftest_llc.c
index a912159693fd..78eab5557df1 100644
--- a/drivers/gpu/drm/i915/gt/selftest_llc.c
+++ b/drivers/gpu/drm/i915/gt/selftest_llc.c
@@ -71,3 +71,42 @@ int st_llc_verify(struct intel_llc *llc)
 {
 	return gen6_verify_ring_freq(llc);
 }
+
+static void override_ia_freq(struct intel_llc *llc,
+			     const struct ia_constants *consts,
+			     bool max,
+			     unsigned int *out_ia_freq,
+			     unsigned int *out_ring_freq)
+{
+	struct drm_i915_private *i915 = llc_to_gt(llc)->i915;
+	unsigned int ia_freq = 0, ring_freq = 0;
+
+	if (INTEL_GEN(i915) <= 7 && !IS_HASWELL(i915))
+		ia_freq = max ? consts->max_ia_freq : 800;
+	else
+		ring_freq = max ? consts->max_gpu_freq : consts->min_gpu_freq;
+
+	*out_ia_freq = ia_freq;
+	*out_ring_freq = ring_freq;
+}
+
+void st_llc_override(struct intel_llc *llc, bool max)
+{
+	struct drm_i915_private *i915 = llc_to_gt(llc)->i915;
+	unsigned int ia_freq, ring_freq, gpu_freq;
+	struct ia_constants consts;
+
+	if (!get_ia_constants(llc, &consts))
+		return;
+
+	override_ia_freq(llc, &consts, max, &ia_freq, &ring_freq);
+	for (gpu_freq = consts.max_gpu_freq;
+	     gpu_freq >= consts.min_gpu_freq;
+	     gpu_freq--) {
+		sandybridge_pcode_write(i915,
+					GEN6_PCODE_WRITE_MIN_FREQ_TABLE,
+					ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT |
+					ring_freq << GEN6_PCODE_FREQ_RING_RATIO_SHIFT |
+					gpu_freq);
+	}
+}
diff --git a/drivers/gpu/drm/i915/gt/selftest_llc.h b/drivers/gpu/drm/i915/gt/selftest_llc.h
index 873f896e72f2..10a86220f5d8 100644
--- a/drivers/gpu/drm/i915/gt/selftest_llc.h
+++ b/drivers/gpu/drm/i915/gt/selftest_llc.h
@@ -7,8 +7,11 @@
 #ifndef SELFTEST_LLC_H
 #define SELFTEST_LLC_H
 
+#include <linux/types.h>
+
 struct intel_llc;
 
 int st_llc_verify(struct intel_llc *llc);
+void st_llc_override(struct intel_llc *llc, bool max);
 
 #endif /* SELFTEST_LLC_H */
diff --git a/drivers/gpu/drm/i915/gt/selftest_rps.c b/drivers/gpu/drm/i915/gt/selftest_rps.c
index 5049c3dd08a6..5cd514ae2d1b 100644
--- a/drivers/gpu/drm/i915/gt/selftest_rps.c
+++ b/drivers/gpu/drm/i915/gt/selftest_rps.c
@@ -12,6 +12,7 @@
 #include "intel_gt_clock_utils.h"
 #include "intel_gt_pm.h"
 #include "intel_rc6.h"
+#include "selftest_llc.h"
 #include "selftest_rps.h"
 #include "selftests/igt_flush_test.h"
 #include "selftests/igt_spinner.h"
@@ -882,6 +883,139 @@ int live_rps_frequency_srm(void *arg)
 	return err;
 }
 
+static unsigned long
+__live_rps_frequency_ring(struct intel_engine_cs *engine, int *freq)
+{
+	struct intel_rps *rps = &engine->gt->rps;
+	struct i915_request *rq;
+	struct i915_vma *vma;
+	unsigned long count;
+	u32 *cancel, *cntr;
+
+	engine_heartbeat_disable(engine);
+
+	vma = create_spin_counter(engine,
+				  engine->kernel_context->vm, true,
+				  &cancel, &cntr);
+	if (IS_ERR(vma)) {
+		engine_heartbeat_enable(engine);
+		return PTR_ERR(vma);
+	}
+
+	rq = intel_engine_create_kernel_request(engine);
+	if (IS_ERR(rq)) {
+		count = PTR_ERR(rq);
+		goto err_vma;
+	}
+
+	i915_vma_lock(vma);
+	count = i915_request_await_object(rq, vma->obj, false);
+	if (!count)
+		count = i915_vma_move_to_active(vma, rq, 0);
+	if (!count)
+		count = rq->engine->emit_bb_start(rq,
+						  vma->node.start,
+						  PAGE_SIZE, 0);
+	i915_vma_unlock(vma);
+	i915_request_add(rq);
+	if (count)
+		goto err_vma;
+
+	if (wait_for(READ_ONCE(*cntr), 10)) {
+		pr_err("%s: timed loop did not start\n",
+		       engine->name);
+		count = -ETIME;
+		goto err_vma;
+	}
+
+	count = measure_frequency_at(rps, cntr, freq);
+
+err_vma:
+	*cancel = MI_BATCH_BUFFER_END;
+	i915_gem_object_flush_map(vma->obj);
+	i915_gem_object_unpin_map(vma->obj);
+	i915_vma_unpin(vma);
+	i915_vma_put(vma);
+
+	engine_heartbeat_enable(engine);
+	if (igt_flush_test(engine->i915))
+		count = -EIO;
+
+	return count;
+}
+
+int live_rps_frequency_ring(void *arg)
+{
+	void (*saved_work)(struct work_struct *wrk);
+	struct intel_gt *gt = arg;
+	struct intel_rps *rps = &gt->rps;
+	struct intel_engine_cs *engine;
+	struct pm_qos_request qos;
+	enum intel_engine_id id;
+	int err = 0;
+
+	if (!intel_rps_is_enabled(rps))
+		return 0;
+
+	if (!HAS_LLC(gt->i915))
+		return 0;
+
+	if (INTEL_GEN(gt->i915) < 8) /* for CS simplicity */
+		return 0;
+
+	if (CPU_LATENCY >= 0)
+		cpu_latency_qos_add_request(&qos, CPU_LATENCY);
+
+	intel_gt_pm_wait_for_idle(gt);
+	saved_work = rps->work.func;
+	rps->work.func = dummy_rps_work;
+
+	for_each_engine(engine, gt, id) {
+		struct {
+			int freq;
+			unsigned long min, max;
+		} result[2];
+		int pass;
+
+		for (pass = 0; pass <= 1; pass++) {
+			int freq = pass ? rps->max_freq : rps->min_freq;
+
+			intel_gt_pm_wait_for_idle(gt);
+			st_llc_override(&gt->llc, false);
+
+			result[pass].min = __live_rps_frequency_ring(engine, &freq);
+			if (IS_ERR_VALUE(result[pass].min)) {
+				err = result[pass].min;
+				break;
+			}
+
+			intel_gt_pm_wait_for_idle(gt);
+			st_llc_override(&gt->llc, true);
+
+			result[pass].max = __live_rps_frequency_ring(engine, &freq);
+			if (IS_ERR_VALUE(result[pass].max)) {
+				err = result[pass].max;
+				break;
+			}
+
+			result[pass].freq = freq;
+		}
+
+		pr_info("%s: freq:%x, min:%lu, max:%lu\n",
+			engine->name, result[0].freq, result[0].min, result[0].max);
+		pr_info("%s: freq:%x, min:%lu, max:%lu\n",
+			engine->name, result[1].freq, result[1].min, result[1].max);
+	}
+
+	intel_gt_pm_wait_for_idle(gt);
+	rps->work.func = saved_work;
+
+	if (CPU_LATENCY >= 0)
+		cpu_latency_qos_remove_request(&qos);
+
+	return err;
+}
+
 static void sleep_for_ei(struct intel_rps *rps, int timeout_us)
 {
 	/* Flush any previous EI */
diff --git a/drivers/gpu/drm/i915/gt/selftest_rps.h b/drivers/gpu/drm/i915/gt/selftest_rps.h
index 6e82a631cfa1..fa3135d9d4ee 100644
--- a/drivers/gpu/drm/i915/gt/selftest_rps.h
+++ b/drivers/gpu/drm/i915/gt/selftest_rps.h
@@ -10,6 +10,7 @@ int live_rps_control(void *arg);
 int live_rps_clock_interval(void *arg);
 int live_rps_frequency_cs(void *arg);
 int live_rps_frequency_srm(void *arg);
+int live_rps_frequency_ring(void *arg);
 int live_rps_power(void *arg);
 int live_rps_interrupt(void *arg);
 int live_rps_dynamic(void *arg);
-- 
2.20.1



More information about the Intel-gfx-trybot mailing list