drm/i915: Relax RPS contraints to allows setting minfreq on idle
authorChris Wilson <chris@chris-wilson.co.uk>
Wed, 18 Mar 2015 09:48:21 +0000 (09:48 +0000)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Fri, 20 Mar 2015 10:48:13 +0000 (11:48 +0100)
When we idle, we set the GPU frequency to the hardware minimum (not user
minimum). We introduce a new variable to distinguish between the
different roles, and to allow easy tuning of the idle frequency without
impacting over aspects of RPS. Setting the minimum frequency should be a
safety blanket as the pcu on the GPU should be power gating itself
anyway. However, in order for us to do set the absolute minimum
frequency, we need to relax a few of our assertions that we do not
exceed the user limits.

v2: Add idle_freq
v3: Init idle_freq for vlv and add a bunch of WARNs

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Deepak S <deepak.s@linux.intel.com>
Reviewed-by: Deepak S<deepak.s@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/intel_pm.c

index aaf7560..007c7d7 100644 (file)
@@ -1200,6 +1200,9 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
 
                seq_printf(m, "Max overclocked frequency: %dMHz\n",
                           intel_gpu_freq(dev_priv, dev_priv->rps.max_freq));
+
+               seq_printf(m, "Idle freq: %d MHz\n",
+                          intel_gpu_freq(dev_priv, dev_priv->rps.idle_freq));
        } else if (IS_VALLEYVIEW(dev)) {
                u32 freq_sts;
 
@@ -1214,6 +1217,9 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
                seq_printf(m, "min GPU freq: %d MHz\n",
                           intel_gpu_freq(dev_priv, dev_priv->rps.min_freq));
 
+               seq_printf(m, "idle GPU freq: %d MHz\n",
+                          intel_gpu_freq(dev_priv, dev_priv->rps.idle_freq));
+
                seq_printf(m,
                           "efficient (RPe) frequency: %d MHz\n",
                           intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq));
index 81f60b4..a06536c 100644 (file)
@@ -1025,6 +1025,7 @@ struct intel_gen6_power_mgmt {
        u8 max_freq_softlimit;  /* Max frequency permitted by the driver */
        u8 max_freq;            /* Maximum frequency, RP0 if not overclocking */
        u8 min_freq;            /* AKA RPn. Minimum frequency */
+       u8 idle_freq;           /* Frequency to request when we are idle */
        u8 efficient_freq;      /* AKA RPe. Pre-determined balanced frequency */
        u8 rp1_freq;            /* "less than" RP0 power/freqency */
        u8 rp0_freq;            /* Non-overclocked max frequency. */
index 288c9d2..beab305 100644 (file)
@@ -3855,9 +3855,9 @@ static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val)
                break;
        }
        /* Max/min bins are special */
-       if (val == dev_priv->rps.min_freq_softlimit)
+       if (val <= dev_priv->rps.min_freq_softlimit)
                new_power = LOW_POWER;
-       if (val == dev_priv->rps.max_freq_softlimit)
+       if (val >= dev_priv->rps.max_freq_softlimit)
                new_power = HIGH_POWER;
        if (new_power == dev_priv->rps.power)
                return;
@@ -3940,8 +3940,8 @@ static void gen6_set_rps(struct drm_device *dev, u8 val)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
-       WARN_ON(val > dev_priv->rps.max_freq_softlimit);
-       WARN_ON(val < dev_priv->rps.min_freq_softlimit);
+       WARN_ON(val > dev_priv->rps.max_freq);
+       WARN_ON(val < dev_priv->rps.min_freq);
 
        /* min/max delay may still have been modified so be sure to
         * write the limits value.
@@ -3979,8 +3979,8 @@ static void valleyview_set_rps(struct drm_device *dev, u8 val)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
-       WARN_ON(val > dev_priv->rps.max_freq_softlimit);
-       WARN_ON(val < dev_priv->rps.min_freq_softlimit);
+       WARN_ON(val > dev_priv->rps.max_freq);
+       WARN_ON(val < dev_priv->rps.min_freq);
 
        if (WARN_ONCE(IS_CHERRYVIEW(dev) && (val & 1),
                      "Odd GPU freq value\n"))
@@ -4007,10 +4007,11 @@ static void valleyview_set_rps(struct drm_device *dev, u8 val)
 static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
 {
        struct drm_device *dev = dev_priv->dev;
+       u32 val = dev_priv->rps.idle_freq;
 
        /* CHV and latest VLV don't need to force the gfx clock */
        if (IS_CHERRYVIEW(dev) || dev->pdev->revision >= 0xd) {
-               valleyview_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
+               valleyview_set_rps(dev_priv->dev, val);
                return;
        }
 
@@ -4018,7 +4019,7 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
         * When we are idle.  Drop to min voltage state.
         */
 
-       if (dev_priv->rps.cur_freq <= dev_priv->rps.min_freq_softlimit)
+       if (dev_priv->rps.cur_freq <= val)
                return;
 
        /* Mask turbo interrupt so that they will not come in between */
@@ -4027,10 +4028,9 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
 
        vlv_force_gfx_clock(dev_priv, true);
 
-       dev_priv->rps.cur_freq = dev_priv->rps.min_freq_softlimit;
+       dev_priv->rps.cur_freq = val;
 
-       vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ,
-                                       dev_priv->rps.min_freq_softlimit);
+       vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
 
        if (wait_for(((vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS))
                                & GENFREQSTATUS) == 0, 100))
@@ -4038,8 +4038,7 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
 
        vlv_force_gfx_clock(dev_priv, false);
 
-       I915_WRITE(GEN6_PMINTRMSK,
-                  gen6_rps_pm_mask(dev_priv, dev_priv->rps.cur_freq));
+       I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val));
 }
 
 void gen6_rps_idle(struct drm_i915_private *dev_priv)
@@ -4051,7 +4050,7 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv)
                if (IS_VALLEYVIEW(dev))
                        vlv_set_rps_idle(dev_priv);
                else
-                       gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
+                       gen6_set_rps(dev_priv->dev, dev_priv->rps.idle_freq);
                dev_priv->rps.last_adj = 0;
        }
        mutex_unlock(&dev_priv->rps.hw_lock);
@@ -4209,6 +4208,8 @@ static void gen6_init_rps_frequencies(struct drm_device *dev)
                                        dev_priv->rps.max_freq);
        }
 
+       dev_priv->rps.idle_freq = dev_priv->rps.min_freq;
+
        /* Preserve min/max settings in case of re-init */
        if (dev_priv->rps.max_freq_softlimit == 0)
                dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
@@ -4375,7 +4376,7 @@ static void gen8_enable_rps(struct drm_device *dev)
        /* 6: Ring frequency + overclocking (our driver does this later */
 
        dev_priv->rps.power = HIGH_POWER; /* force a reset */
-       gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
+       gen6_set_rps(dev_priv->dev, dev_priv->rps.idle_freq);
 
        intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 }
@@ -4469,7 +4470,7 @@ static void gen6_enable_rps(struct drm_device *dev)
        }
 
        dev_priv->rps.power = HIGH_POWER; /* force a reset */
-       gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
+       gen6_set_rps(dev_priv->dev, dev_priv->rps.idle_freq);
 
        rc6vids = 0;
        ret = sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_RC6VIDS, &rc6vids);
@@ -4834,6 +4835,8 @@ static void valleyview_init_gt_powersave(struct drm_device *dev)
                         intel_gpu_freq(dev_priv, dev_priv->rps.min_freq),
                         dev_priv->rps.min_freq);
 
+       dev_priv->rps.idle_freq = dev_priv->rps.min_freq;
+
        /* Preserve min/max settings in case of re-init */
        if (dev_priv->rps.max_freq_softlimit == 0)
                dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
@@ -4909,6 +4912,8 @@ static void cherryview_init_gt_powersave(struct drm_device *dev)
                   dev_priv->rps.min_freq) & 1,
                  "Odd GPU freq values\n");
 
+       dev_priv->rps.idle_freq = dev_priv->rps.min_freq;
+
        /* Preserve min/max settings in case of re-init */
        if (dev_priv->rps.max_freq_softlimit == 0)
                dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
@@ -5686,6 +5691,13 @@ static void intel_gen6_powersave_work(struct work_struct *work)
                gen6_enable_rps(dev);
                __gen6_update_ring_freq(dev);
        }
+
+       WARN_ON(dev_priv->rps.max_freq < dev_priv->rps.min_freq);
+       WARN_ON(dev_priv->rps.idle_freq > dev_priv->rps.max_freq);
+
+       WARN_ON(dev_priv->rps.efficient_freq < dev_priv->rps.min_freq);
+       WARN_ON(dev_priv->rps.efficient_freq > dev_priv->rps.max_freq);
+
        dev_priv->rps.enabled = true;
 
        gen6_enable_rps_interrupts(dev);