diff mbox

drm/i915: initialize ring frequency scaling table on SNB

Message ID 20110623101126.58cba07c@jbarnes-desktop (mailing list archive)
State New, archived
Headers show

Commit Message

Jesse Barnes June 23, 2011, 5:11 p.m. UTC
I tested again and things were working as expected.  This patch adds a
debugfs file for dumping the ring freq table, can you guys test it out
(try disabling the call to update the table, dump it, make sure it's 0,
then re-enable and make sure it's programmed correctly).

Comments

Chris Wilson June 23, 2011, 8:08 p.m. UTC | #1
On Thu, 23 Jun 2011 10:11:26 -0700, Jesse Barnes <jbarnes@virtuousgeek.org> wrote:
> I tested again and things were working as expected.  This patch adds a
> debugfs file for dumping the ring freq table, can you guys test it out
> (try disabling the call to update the table, dump it, make sure it's 0,
> then re-enable and make sure it's programmed correctly).

According to the debugfs, your defaults should be effective:

sandybridge:~$ cat /sys/kernel/debug/dri/1/i915_ring_freq_table 
GPU freq	Effective CPU freq
850		0 -> 1600
900		0 -> 1700
950		0 -> 1800
1000		0 -> 1800
1050		0 -> 1900
1100		0 -> 2000

I'll give the tyres another kick and see if I can spot any differences.
-Chris
Jesse Barnes June 23, 2011, 8:16 p.m. UTC | #2
On Thu, 23 Jun 2011 21:08:02 +0100
Chris Wilson <chris@chris-wilson.co.uk> wrote:

> On Thu, 23 Jun 2011 10:11:26 -0700, Jesse Barnes <jbarnes@virtuousgeek.org> wrote:
> > I tested again and things were working as expected.  This patch adds a
> > debugfs file for dumping the ring freq table, can you guys test it out
> > (try disabling the call to update the table, dump it, make sure it's 0,
> > then re-enable and make sure it's programmed correctly).
> 
> According to the debugfs, your defaults should be effective:
> 
> sandybridge:~$ cat /sys/kernel/debug/dri/1/i915_ring_freq_table 
> GPU freq	Effective CPU freq
> 850		0 -> 1600
> 900		0 -> 1700
> 950		0 -> 1800
> 1000		0 -> 1800
> 1050		0 -> 1900
> 1100		0 -> 2000
> 
> I'll give the tyres another kick and see if I can spot any differences.

Eric was seeing an increase, but not as large as expected or hoped
for.  He saw a greater increase in performance than this patch provides
by simply keeping the CPU busy during his benchmark.  That could be due
to additional ring frequency when the CPU is in a turbo mode.  You may
be able to approach that by making the effective CPU frequency much
higher (maybe going up to 4GHz).
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 4d46441..79394cd 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1123,6 +1123,48 @@  static int i915_emon_status(struct seq_file *m, void *unused)
 	return 0;
 }
 
+static int i915_ring_freq_table(struct seq_file *m, void *unused)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	int ret;
+	int gpu_freq, ia_freq;
+
+	if (!IS_GEN6(dev)) {
+		seq_printf(m, "unsupported on this chipset\n");
+		return 0;
+	}
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
+
+	gen6_gt_force_wake_get(dev_priv);
+
+	seq_printf(m, "GPU freq\tEffective CPU freq\n");
+
+	for (gpu_freq = dev_priv->min_delay; gpu_freq <= dev_priv->max_delay;
+	     gpu_freq++) {
+		I915_WRITE(GEN6_PCODE_DATA, gpu_freq);
+		I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY |
+			   GEN6_PCODE_READ_MIN_FREQ_TABLE);
+		if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) &
+			      GEN6_PCODE_READY) == 0, 10)) {
+			DRM_ERROR("pcode write of freq table timed out\n");
+			continue;
+		}
+		ia_freq = I915_READ(GEN6_PCODE_DATA);
+		seq_printf(m, "%d\t\t%d\n", gpu_freq * 50, ia_freq * 100);
+	}
+
+	gen6_gt_force_wake_put(dev_priv);
+
+	mutex_unlock(&dev->struct_mutex);
+
+	return 0;
+}
+
 static int i915_gfxec(struct seq_file *m, void *unused)
 {
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -1426,6 +1468,7 @@  static struct drm_info_list i915_debugfs_list[] = {
 	{"i915_inttoext_table", i915_inttoext_table, 0},
 	{"i915_drpc_info", i915_drpc_info, 0},
 	{"i915_emon_status", i915_emon_status, 0},
+	{"i915_ring_freq_table", i915_ring_freq_table, 0},
 	{"i915_gfxec", i915_gfxec, 0},
 	{"i915_fbc_status", i915_fbc_status, 0},
 	{"i915_sr_status", i915_sr_status, 0},
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 2f967af..757e024 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -3433,7 +3433,9 @@ 
 #define GEN6_PCODE_MAILBOX			0x138124
 #define   GEN6_PCODE_READY			(1<<31)
 #define   GEN6_READ_OC_PARAMS			0xc
-#define   GEN6_PCODE_WRITE_MIN_FREQ_TABLE	0x9
+#define   GEN6_PCODE_WRITE_MIN_FREQ_TABLE	0x8
+#define   GEN6_PCODE_READ_MIN_FREQ_TABLE	0x9
 #define GEN6_PCODE_DATA				0x138128
+#define   GEN6_PCODE_FREQ_IA_RATIO_SHIFT	8
 
 #endif /* _I915_REG_H_ */
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 60a94d2..03f0fac 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -870,8 +870,10 @@  int i915_restore_state(struct drm_device *dev)
 		intel_init_emon(dev);
 	}
 
-	if (IS_GEN6(dev))
+	if (IS_GEN6(dev)) {
 		gen6_enable_rps(dev_priv);
+		gen6_update_ring_freq(dev_priv);
+	}
 
 	/* Cache mode state */
 	I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 86a3ec1..05c28eb 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -7159,6 +7159,46 @@  void gen6_enable_rps(struct drm_i915_private *dev_priv)
 	mutex_unlock(&dev_priv->dev->struct_mutex);
 }
 
+void gen6_update_ring_freq(struct drm_i915_private *dev_priv)
+{
+	int min_freq = 15, max_freq = 32;
+	int gpu_freq, ia_freq;
+	int scaling_factor = 180;
+
+	mutex_lock(&dev_priv->dev->struct_mutex);
+	gen6_gt_force_wake_get(dev_priv);
+
+	/*
+	 * For each potential GPU frequency, load a ring frequency we'd like
+	 * to use for memory access.  We do this by specifying the IA frequency
+	 * the PCU should use as a reference to determine the ring frequency.
+	 */
+	for (gpu_freq = dev_priv->min_delay; gpu_freq <= dev_priv->max_delay;
+	     gpu_freq++) {
+		if (gpu_freq < min_freq) /* Use 800MHz min IA reference freq */
+			ia_freq = 800;
+		else if (gpu_freq > max_freq) /* Clamp to 3GHz IA ref. freq */
+			ia_freq = 3000;
+		else
+			ia_freq = (gpu_freq * scaling_factor) / 2;
+		ia_freq = DIV_ROUND_UP(ia_freq, 100);
+
+		I915_WRITE(GEN6_PCODE_DATA,
+			   (ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT) |
+			   gpu_freq);
+		I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY |
+			   GEN6_PCODE_WRITE_MIN_FREQ_TABLE);
+		if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) &
+			      GEN6_PCODE_READY) == 0, 10)) {
+			DRM_ERROR("pcode write of freq table timed out\n");
+			continue;
+		}
+	}
+
+	gen6_gt_force_wake_put(dev_priv);
+	mutex_unlock(&dev_priv->dev->struct_mutex);
+}
+
 static void ironlake_init_clock_gating(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -7777,8 +7817,10 @@  void intel_modeset_init(struct drm_device *dev)
 		intel_init_emon(dev);
 	}
 
-	if (IS_GEN6(dev))
+	if (IS_GEN6(dev)) {
 		gen6_enable_rps(dev_priv);
+		gen6_update_ring_freq(dev_priv);
+	}
 
 	INIT_WORK(&dev_priv->idle_work, intel_idle_update);
 	setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 9ffa61e..8ac3bd8 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -317,6 +317,7 @@  extern void intel_enable_clock_gating(struct drm_device *dev);
 extern void ironlake_enable_drps(struct drm_device *dev);
 extern void ironlake_disable_drps(struct drm_device *dev);
 extern void gen6_enable_rps(struct drm_i915_private *dev_priv);
+extern void gen6_update_ring_freq(struct drm_i915_private *dev_priv);
 extern void gen6_disable_rps(struct drm_device *dev);
 extern void intel_init_emon(struct drm_device *dev);