diff mbox

[1/3] drm/i915: Extract PCU communication

Message ID 1348680842-3036-1-git-send-email-ben@bwidawsk.net (mailing list archive)
State New, archived
Headers show

Commit Message

Ben Widawsky Sept. 26, 2012, 5:34 p.m. UTC
There is a special mechanism for communicating with the PCU already
being used for the ring frequency stuff. As we'll be needing this for
other commands, extract it now to make future code less error prone and
the current code more reusable.

I'm not entirely sure if this code matches 1:1 with the previous code
behaviorally. Functionally however, it should be the same.

CC: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
---
 drivers/gpu/drm/i915/i915_debugfs.c | 13 ++---
 drivers/gpu/drm/i915/i915_drv.h     |  3 ++
 drivers/gpu/drm/i915/intel_pm.c     | 94 +++++++++++++++++++++++--------------
 3 files changed, 67 insertions(+), 43 deletions(-)

Comments

Jesse Barnes Sept. 27, 2012, 6:05 p.m. UTC | #1
On Wed, 26 Sep 2012 10:34:00 -0700
Ben Widawsky <ben@bwidawsk.net> wrote:

> There is a special mechanism for communicating with the PCU already
> being used for the ring frequency stuff. As we'll be needing this for
> other commands, extract it now to make future code less error prone and
> the current code more reusable.
> 
> I'm not entirely sure if this code matches 1:1 with the previous code
> behaviorally. Functionally however, it should be the same.
> 
> CC: Jesse Barnes <jbarnes@virtuousgeek.org>
> Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
> ---
>  drivers/gpu/drm/i915/i915_debugfs.c | 13 ++---
>  drivers/gpu/drm/i915/i915_drv.h     |  3 ++
>  drivers/gpu/drm/i915/intel_pm.c     | 94 +++++++++++++++++++++++--------------
>  3 files changed, 67 insertions(+), 43 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index 7a4b3f3..6647585 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -1283,15 +1283,10 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
>  	for (gpu_freq = dev_priv->rps.min_delay;
>  	     gpu_freq <= dev_priv->rps.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 read of freq table timed out\n");
> -			continue;
> -		}
> -		ia_freq = I915_READ(GEN6_PCODE_DATA);
> +		ia_freq = gpu_freq;
> +		sandybridge_pcode_read(dev_priv,
> +				       GEN6_PCODE_READ_MIN_FREQ_TABLE,
> +				       &ia_freq);
>  		seq_printf(m, "%d\t\t%d\n", gpu_freq * GT_FREQUENCY_MULTIPLIER, ia_freq * 100);
>  	}
>  
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index af5ceb4..b75a7b5 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1622,6 +1622,9 @@ void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv);
>  void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv);
>  int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
>  
> +int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val);
> +int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val);
> +
>  #define __i915_read(x, y) \
>  	u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg);
>  
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index a3e4f8b..6488cd0 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -2503,30 +2503,16 @@ static void gen6_enable_rps(struct drm_device *dev)
>  		   GEN6_RP_UP_BUSY_AVG |
>  		   (IS_HASWELL(dev) ? GEN7_RP_DOWN_IDLE_AVG : GEN6_RP_DOWN_IDLE_CONT));
>  
> -	if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
> -		     500))
> -		DRM_ERROR("timeout waiting for pcode mailbox to become idle\n");
> -
> -	I915_WRITE(GEN6_PCODE_DATA, 0);
> -	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,
> -		     500))
> -		DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
> -
> -	/* Check for overclock support */
> -	if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
> -		     500))
> -		DRM_ERROR("timeout waiting for pcode mailbox to become idle\n");
> -	I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_READ_OC_PARAMS);
> -	pcu_mbox = I915_READ(GEN6_PCODE_DATA);
> -	if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
> -		     500))
> -		DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
> -	if (pcu_mbox & (1<<31)) { /* OC supported */
> -		dev_priv->rps.max_delay = pcu_mbox & 0xff;
> -		DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50);
> +	ret = sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_MIN_FREQ_TABLE, 0);
> +	if (!ret) {
> +		pcu_mbox = 0;
> +		ret = sandybridge_pcode_read(dev_priv, GEN6_READ_OC_PARAMS, &pcu_mbox);
> +		if (ret && pcu_mbox & (1<<31)) { /* OC supported */
> +			dev_priv->rps.max_delay = pcu_mbox & 0xff;
> +			DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50);
> +		}
> +	} else {
> +		DRM_DEBUG_DRIVER("Failed to set the min frequency\n");
>  	}
>  
>  	gen6_set_rps(dev_priv->dev, (gt_perf_status & 0xff00) >> 8);
> @@ -2581,17 +2567,11 @@ static void gen6_update_ring_freq(struct drm_device *dev)
>  		else
>  			ia_freq = max_ia_freq - ((diff * scaling_factor) / 2);
>  		ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100);
> +		ia_freq <<= GEN6_PCODE_FREQ_IA_RATIO_SHIFT;
>  
> -		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;
> -		}
> +		sandybridge_pcode_write(dev_priv,
> +					GEN6_PCODE_WRITE_MIN_FREQ_TABLE,
> +					ia_freq | gpu_freq);
>  	}
>  }
>  
> @@ -4143,3 +4123,49 @@ void intel_gt_init(struct drm_device *dev)
>  	}
>  }
>  
> +int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val)
> +{
> +	WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
> +
> +	if (I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) {
> +		DRM_DEBUG_DRIVER("warning: pcode (read) mailbox access failed\n");
> +		return -EAGAIN;
> +	}
> +
> +	I915_WRITE(GEN6_PCODE_DATA, *val);
> +	I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | mbox);
> +
> +	if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
> +		     500)) {
> +		DRM_ERROR("timeout waiting for pcode read (%d) to finish\n", mbox);
> +		return -ETIMEDOUT;
> +	}
> +
> +	*val = I915_READ(GEN6_PCODE_DATA);
> +	I915_WRITE(GEN6_PCODE_DATA, 0);
> +
> +	return 0;
> +}
> +
> +int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val)
> +{
> +	WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
> +
> +	if (I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) {
> +		DRM_DEBUG_DRIVER("warning: pcode (write) mailbox access failed\n");
> +		return -EAGAIN;
> +	}
> +
> +	I915_WRITE(GEN6_PCODE_DATA, val);
> +	I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | mbox);
> +
> +	if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
> +		     500)) {
> +		DRM_ERROR("timeout waiting for pcode write (%d) to finish\n", mbox);
> +		return -ETIMEDOUT;
> +	}
> +
> +	I915_WRITE(GEN6_PCODE_DATA, 0);
> +
> +	return 0;
> +}

I'd call it punit rather than pcode, but that's just a nitpick.  I like
pulling it out into a separate function.

Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 7a4b3f3..6647585 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1283,15 +1283,10 @@  static int i915_ring_freq_table(struct seq_file *m, void *unused)
 	for (gpu_freq = dev_priv->rps.min_delay;
 	     gpu_freq <= dev_priv->rps.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 read of freq table timed out\n");
-			continue;
-		}
-		ia_freq = I915_READ(GEN6_PCODE_DATA);
+		ia_freq = gpu_freq;
+		sandybridge_pcode_read(dev_priv,
+				       GEN6_PCODE_READ_MIN_FREQ_TABLE,
+				       &ia_freq);
 		seq_printf(m, "%d\t\t%d\n", gpu_freq * GT_FREQUENCY_MULTIPLIER, ia_freq * 100);
 	}
 
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index af5ceb4..b75a7b5 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1622,6 +1622,9 @@  void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv);
 void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv);
 int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
 
+int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val);
+int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val);
+
 #define __i915_read(x, y) \
 	u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg);
 
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index a3e4f8b..6488cd0 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2503,30 +2503,16 @@  static void gen6_enable_rps(struct drm_device *dev)
 		   GEN6_RP_UP_BUSY_AVG |
 		   (IS_HASWELL(dev) ? GEN7_RP_DOWN_IDLE_AVG : GEN6_RP_DOWN_IDLE_CONT));
 
-	if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
-		     500))
-		DRM_ERROR("timeout waiting for pcode mailbox to become idle\n");
-
-	I915_WRITE(GEN6_PCODE_DATA, 0);
-	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,
-		     500))
-		DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
-
-	/* Check for overclock support */
-	if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
-		     500))
-		DRM_ERROR("timeout waiting for pcode mailbox to become idle\n");
-	I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_READ_OC_PARAMS);
-	pcu_mbox = I915_READ(GEN6_PCODE_DATA);
-	if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
-		     500))
-		DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
-	if (pcu_mbox & (1<<31)) { /* OC supported */
-		dev_priv->rps.max_delay = pcu_mbox & 0xff;
-		DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50);
+	ret = sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_MIN_FREQ_TABLE, 0);
+	if (!ret) {
+		pcu_mbox = 0;
+		ret = sandybridge_pcode_read(dev_priv, GEN6_READ_OC_PARAMS, &pcu_mbox);
+		if (ret && pcu_mbox & (1<<31)) { /* OC supported */
+			dev_priv->rps.max_delay = pcu_mbox & 0xff;
+			DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50);
+		}
+	} else {
+		DRM_DEBUG_DRIVER("Failed to set the min frequency\n");
 	}
 
 	gen6_set_rps(dev_priv->dev, (gt_perf_status & 0xff00) >> 8);
@@ -2581,17 +2567,11 @@  static void gen6_update_ring_freq(struct drm_device *dev)
 		else
 			ia_freq = max_ia_freq - ((diff * scaling_factor) / 2);
 		ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100);
+		ia_freq <<= GEN6_PCODE_FREQ_IA_RATIO_SHIFT;
 
-		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;
-		}
+		sandybridge_pcode_write(dev_priv,
+					GEN6_PCODE_WRITE_MIN_FREQ_TABLE,
+					ia_freq | gpu_freq);
 	}
 }
 
@@ -4143,3 +4123,49 @@  void intel_gt_init(struct drm_device *dev)
 	}
 }
 
+int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val)
+{
+	WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
+
+	if (I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) {
+		DRM_DEBUG_DRIVER("warning: pcode (read) mailbox access failed\n");
+		return -EAGAIN;
+	}
+
+	I915_WRITE(GEN6_PCODE_DATA, *val);
+	I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | mbox);
+
+	if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
+		     500)) {
+		DRM_ERROR("timeout waiting for pcode read (%d) to finish\n", mbox);
+		return -ETIMEDOUT;
+	}
+
+	*val = I915_READ(GEN6_PCODE_DATA);
+	I915_WRITE(GEN6_PCODE_DATA, 0);
+
+	return 0;
+}
+
+int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val)
+{
+	WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
+
+	if (I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) {
+		DRM_DEBUG_DRIVER("warning: pcode (write) mailbox access failed\n");
+		return -EAGAIN;
+	}
+
+	I915_WRITE(GEN6_PCODE_DATA, val);
+	I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | mbox);
+
+	if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
+		     500)) {
+		DRM_ERROR("timeout waiting for pcode write (%d) to finish\n", mbox);
+		return -ETIMEDOUT;
+	}
+
+	I915_WRITE(GEN6_PCODE_DATA, 0);
+
+	return 0;
+}