return 0;
        }
 
-       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
        if (ret)
                return ret;
 
                seq_printf(m, "%d\t\t%d\n", gpu_freq * GT_FREQUENCY_MULTIPLIER, ia_freq * 100);
        }
 
-       mutex_unlock(&dev->struct_mutex);
+       mutex_unlock(&dev_priv->rps.hw_lock);
 
        return 0;
 }
        if (!(IS_GEN6(dev) || IS_GEN7(dev)))
                return -ENODEV;
 
-       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
        if (ret)
                return ret;
 
        len = snprintf(buf, sizeof(buf),
                       "max freq: %d\n", dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER);
-       mutex_unlock(&dev->struct_mutex);
+       mutex_unlock(&dev_priv->rps.hw_lock);
 
        if (len > sizeof(buf))
                len = sizeof(buf);
 
        DRM_DEBUG_DRIVER("Manually setting max freq to %d\n", val);
 
-       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
        if (ret)
                return ret;
 
        dev_priv->rps.max_delay = val / GT_FREQUENCY_MULTIPLIER;
 
        gen6_set_rps(dev, val / GT_FREQUENCY_MULTIPLIER);
-       mutex_unlock(&dev->struct_mutex);
+       mutex_unlock(&dev_priv->rps.hw_lock);
 
        return cnt;
 }
        if (!(IS_GEN6(dev) || IS_GEN7(dev)))
                return -ENODEV;
 
-       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
        if (ret)
                return ret;
 
        len = snprintf(buf, sizeof(buf),
                       "min freq: %d\n", dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER);
-       mutex_unlock(&dev->struct_mutex);
+       mutex_unlock(&dev_priv->rps.hw_lock);
 
        if (len > sizeof(buf))
                len = sizeof(buf);
 
        DRM_DEBUG_DRIVER("Manually setting min freq to %d\n", val);
 
-       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
        if (ret)
                return ret;
 
        dev_priv->rps.min_delay = val / GT_FREQUENCY_MULTIPLIER;
 
        gen6_set_rps(dev, val / GT_FREQUENCY_MULTIPLIER);
-       mutex_unlock(&dev->struct_mutex);
+       mutex_unlock(&dev_priv->rps.hw_lock);
 
        return cnt;
 }
 
        spin_lock_init(&dev_priv->rps.lock);
        spin_lock_init(&dev_priv->dpio_lock);
 
+       mutex_init(&dev_priv->rps.hw_lock);
+
        if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
                dev_priv->num_pipe = 3;
        else if (IS_MOBILE(dev) || !IS_GEN2(dev))
 
        u8 max_delay;
 
        struct delayed_work delayed_resume_work;
+
+       /*
+        * Protects RPS/RC6 register access and PCU communication.
+        * Must be taken after struct_mutex if nested.
+        */
+       struct mutex hw_lock;
 };
 
 struct intel_ilk_power_mgmt {
 
        if ((pm_iir & GEN6_PM_DEFERRED_EVENTS) == 0)
                return;
 
-       mutex_lock(&dev_priv->dev->struct_mutex);
+       mutex_lock(&dev_priv->rps.hw_lock);
 
        if (pm_iir & GEN6_PM_RP_UP_THRESHOLD)
                new_delay = dev_priv->rps.cur_delay + 1;
                gen6_set_rps(dev_priv->dev, new_delay);
        }
 
-       mutex_unlock(&dev_priv->dev->struct_mutex);
+       mutex_unlock(&dev_priv->rps.hw_lock);
 }
 
 
 
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
-       ret = i915_mutex_lock_interruptible(dev);
-       if (ret)
-               return ret;
-
+       mutex_lock(&dev_priv->rps.hw_lock);
        ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER;
-       mutex_unlock(&dev->struct_mutex);
+       mutex_unlock(&dev_priv->rps.hw_lock);
 
        return snprintf(buf, PAGE_SIZE, "%d", ret);
 }
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
-       ret = i915_mutex_lock_interruptible(dev);
-       if (ret)
-               return ret;
-
+       mutex_lock(&dev_priv->rps.hw_lock);
        ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER;
-       mutex_unlock(&dev->struct_mutex);
+       mutex_unlock(&dev_priv->rps.hw_lock);
 
        return snprintf(buf, PAGE_SIZE, "%d", ret);
 }
 
        val /= GT_FREQUENCY_MULTIPLIER;
 
-       ret = mutex_lock_interruptible(&dev->struct_mutex);
-       if (ret)
-               return ret;
+       mutex_lock(&dev_priv->rps.hw_lock);
 
        rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
        hw_max = (rp_state_cap & 0xff);
        hw_min = ((rp_state_cap & 0xff0000) >> 16);
 
        if (val < hw_min || val > hw_max || val < dev_priv->rps.min_delay) {
-               mutex_unlock(&dev->struct_mutex);
+               mutex_unlock(&dev_priv->rps.hw_lock);
                return -EINVAL;
        }
 
 
        dev_priv->rps.max_delay = val;
 
-       mutex_unlock(&dev->struct_mutex);
+       mutex_unlock(&dev_priv->rps.hw_lock);
 
        return count;
 }
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
-       ret = i915_mutex_lock_interruptible(dev);
-       if (ret)
-               return ret;
-
+       mutex_lock(&dev_priv->rps.hw_lock);
        ret = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER;
-       mutex_unlock(&dev->struct_mutex);
+       mutex_unlock(&dev_priv->rps.hw_lock);
 
        return snprintf(buf, PAGE_SIZE, "%d", ret);
 }
 
        val /= GT_FREQUENCY_MULTIPLIER;
 
-       ret = mutex_lock_interruptible(&dev->struct_mutex);
-       if (ret)
-               return ret;
+       mutex_lock(&dev_priv->rps.hw_lock);
 
        rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
        hw_max = (rp_state_cap & 0xff);
        hw_min = ((rp_state_cap & 0xff0000) >> 16);
 
        if (val < hw_min || val > hw_max || val > dev_priv->rps.max_delay) {
-               mutex_unlock(&dev->struct_mutex);
+               mutex_unlock(&dev_priv->rps.hw_lock);
                return -EINVAL;
        }
 
 
        dev_priv->rps.min_delay = val;
 
-       mutex_unlock(&dev->struct_mutex);
+       mutex_unlock(&dev_priv->rps.hw_lock);
 
        return count;
 
 
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 limits = gen6_rps_limits(dev_priv, &val);
 
-       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+       WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
        WARN_ON(val > dev_priv->rps.max_delay);
        WARN_ON(val < dev_priv->rps.min_delay);
 
        int rc6_mode;
        int i, ret;
 
-       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+       WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
 
        /* Here begins a magic sequence of register writes to enable
         * auto-downclocking.
        int gpu_freq, ia_freq, max_ia_freq;
        int scaling_factor = 180;
 
-       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+       WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
 
        max_ia_freq = cpufreq_quick_get_max(0);
        /*
                ironlake_disable_rc6(dev);
        } else if (INTEL_INFO(dev)->gen >= 6 && !IS_VALLEYVIEW(dev)) {
                cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work);
+               mutex_lock(&dev_priv->rps.hw_lock);
                gen6_disable_rps(dev);
+               mutex_unlock(&dev_priv->rps.hw_lock);
        }
 }
 
                             rps.delayed_resume_work.work);
        struct drm_device *dev = dev_priv->dev;
 
-       mutex_lock(&dev->struct_mutex);
+       mutex_lock(&dev_priv->rps.hw_lock);
        gen6_enable_rps(dev);
        gen6_update_ring_freq(dev);
-       mutex_unlock(&dev->struct_mutex);
+       mutex_unlock(&dev_priv->rps.hw_lock);
 }
 
 void intel_enable_gt_powersave(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));
+       WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
 
        if (I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) {
                DRM_DEBUG_DRIVER("warning: pcode (read) mailbox access failed\n");
 
 int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val)
 {
-       WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
+       WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
 
        if (I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) {
                DRM_DEBUG_DRIVER("warning: pcode (write) mailbox access failed\n");