drm/i915: protect RPS/RC6 related accesses (including PCU) with a new mutex
authorJesse Barnes <jbarnes@virtuousgeek.org>
Fri, 2 Nov 2012 18:14:01 +0000 (11:14 -0700)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Sun, 11 Nov 2012 22:51:41 +0000 (23:51 +0100)
This allows the power related code to run independently of the rest of
the pipeline, extending the resume and init time improvements into
userspace, which would otherwise have been blocked on the struct mutex
if we were doing PCU communication.

v2: Also convert the locking for the rps sysfs interface.

Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> (v1)
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_sysfs.c
drivers/gpu/drm/i915/intel_pm.c

index 598987ff4fec620b32a388dca76b28b02c34421b..09cd7d76f6aed46e8b7d391f4273f79179eeed1d 100644 (file)
@@ -1280,7 +1280,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
                return 0;
        }
 
-       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
        if (ret)
                return ret;
 
@@ -1296,7 +1296,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
                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;
 }
@@ -1713,13 +1713,13 @@ i915_max_freq_read(struct file *filp,
        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);
@@ -1754,7 +1754,7 @@ i915_max_freq_write(struct file *filp,
 
        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;
 
@@ -1764,7 +1764,7 @@ i915_max_freq_write(struct file *filp,
        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;
 }
@@ -1789,13 +1789,13 @@ i915_min_freq_read(struct file *filp, char __user *ubuf, size_t max,
        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);
@@ -1828,7 +1828,7 @@ i915_min_freq_write(struct file *filp, const char __user *ubuf, size_t cnt,
 
        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;
 
@@ -1838,7 +1838,7 @@ i915_min_freq_write(struct file *filp, const char __user *ubuf, size_t cnt,
        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;
 }
index 530cf90d13b0ebd1b91670fdd4a8b6115073a728..4f3c9337df9099a4fd36a9504aa32df802ea254e 100644 (file)
@@ -1625,6 +1625,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        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))
index 8db7bb9899b93b0650ad4852f843c778cfe4acf6..c4339c2b1b57e8bffa9e4b95d42e88e23e6c89a9 100644 (file)
@@ -564,6 +564,12 @@ struct intel_gen6_power_mgmt {
        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 {
index 2c40127573e2ab6634b65a5b4d9cffeb6751cec8..2604867e6b7dd74e441cbf7b727a46bd2131a7db 100644 (file)
@@ -378,7 +378,7 @@ static void gen6_pm_rps_work(struct work_struct *work)
        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;
@@ -393,7 +393,7 @@ static void gen6_pm_rps_work(struct work_struct *work)
                gen6_set_rps(dev_priv->dev, new_delay);
        }
 
-       mutex_unlock(&dev_priv->dev->struct_mutex);
+       mutex_unlock(&dev_priv->rps.hw_lock);
 }
 
 
index 9700ae96ec193691dc610d4fbdc38f1507bc9d9e..3bf51d58319df03b08ee38e3fe89d78f37022bf3 100644 (file)
@@ -211,12 +211,9 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
        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);
 }
@@ -228,12 +225,9 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute
        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);
 }
@@ -254,16 +248,14 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
 
        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;
        }
 
@@ -272,7 +264,7 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
 
        dev_priv->rps.max_delay = val;
 
-       mutex_unlock(&dev->struct_mutex);
+       mutex_unlock(&dev_priv->rps.hw_lock);
 
        return count;
 }
@@ -284,12 +276,9 @@ static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute
        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);
 }
@@ -310,16 +299,14 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
 
        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;
        }
 
@@ -328,7 +315,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
 
        dev_priv->rps.min_delay = val;
 
-       mutex_unlock(&dev->struct_mutex);
+       mutex_unlock(&dev_priv->rps.hw_lock);
 
        return count;
 
index 169b416430db2e602142df08bc8e6f14e6f9f984..8f1561616bfb95fd77cc16697d1313828337c36b 100644 (file)
@@ -2323,7 +2323,7 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
        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);
 
@@ -2409,7 +2409,7 @@ static void gen6_enable_rps(struct drm_device *dev)
        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.
@@ -2550,7 +2550,7 @@ static void gen6_update_ring_freq(struct drm_device *dev)
        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);
        /*
@@ -3311,7 +3311,9 @@ void intel_disable_gt_powersave(struct drm_device *dev)
                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);
        }
 }
 
@@ -3322,10 +3324,10 @@ static void intel_gen6_powersave_work(struct work_struct *work)
                             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)
@@ -4245,7 +4247,7 @@ 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));
+       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");
@@ -4269,7 +4271,7 @@ 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)
 {
-       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");