@@ -6603,14 +6603,27 @@ static int ironlake_setup_rc6(struct drm_device *dev)
return 0;
}
+static int ironlake_wait_set_context(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring = LP_RING(dev_priv);
+ int ret = -EAGAIN;
+
+ ret = wait_for((I915_READ_HEAD(ring) == I915_READ_TAIL(ring)), 1000);
+ if (ret && atomic_read(&dev_priv->mm.wedged)) {
+ ret = -EIO;
+ } else if (!ret) { /* head == tail */
+ ret = 0;
+ }
+
+ return ret;
+}
+
void ironlake_enable_rc6(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
- /* rc6 disabled by default due to repeated reports of hanging during
- * boot and resume.
- */
if (!i915_enable_rc6)
return;
@@ -6640,6 +6653,19 @@ void ironlake_enable_rc6(struct drm_device *dev)
OUT_RING(MI_FLUSH);
ADVANCE_LP_RING();
+ /*
+ * Wait for the command parser to advance past MI_SET_CONTEXT. The HW
+ * does an implicit flush, combined with MI_FLUSH above, it should be
+ * safe to assume that renderctx is valid
+ */
+ ret = ironlake_wait_set_context(dev);
+ if (ret) {
+ if (ret == -EAGAIN)
+ DRM_ERROR("rc6 switch took too long, freeing the bo");
+ ironlake_teardown_rc6(dev, true);
+ return;
+ }
+
I915_WRITE(PWRCTXA, dev_priv->pwrctx->gtt_offset | PWRCTX_EN);
I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
}