]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
drm/i915: Implement a better i945gm vblank irq vs. C-states workaround
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Thu, 3 Oct 2019 14:02:31 +0000 (17:02 +0300)
committerVille Syrjälä <ville.syrjala@linux.intel.com>
Fri, 4 Oct 2019 15:43:49 +0000 (18:43 +0300)
The current "disable C3+" workaround for the delayed vblank
irqs on i945gm no longer works. I'm not sure what changed, but
now I need to also disable C2. I also got my hands on a i915gm
machine that suffers from the same issue.

After some furious poking of registers I managed to find a
better workaround: The "Do not Turn off Core Render Clock in C
states" bit. With that I no longer have to disable any C-states,
and as a nice bonus the power cost is only ~1/4 of the
"disable C3+" method (which mind you doesn't even work anymore,
and so would have an even higher power cost if we made it work
by also disabling C2).

So let's throw out all the cpuidle/qos crap and just toggle
the magic bit as needed. And we extend the workaround to cover
i915gm as well.

Cc: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191003140231.24408-1-ville.syrjala@linux.intel.com
Acked-by: Chris Wilson <chris@chris-wilson.co.uk>
drivers/gpu/drm/i915/display/intel_display.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_irq.h
drivers/gpu/drm/i915/i915_reg.h

index f3a94a9cff1631e3c57424edc3dd904384de21bd..5acc39f32d0c9c6ad358f0e3659c455ad682dd25 100644 (file)
@@ -15060,12 +15060,12 @@ static const struct drm_crtc_funcs i965_crtc_funcs = {
        .disable_vblank = i965_disable_vblank,
 };
 
-static const struct drm_crtc_funcs i945gm_crtc_funcs = {
+static const struct drm_crtc_funcs i915gm_crtc_funcs = {
        INTEL_CRTC_FUNCS,
 
        .get_vblank_counter = i915_get_vblank_counter,
-       .enable_vblank = i945gm_enable_vblank,
-       .disable_vblank = i945gm_disable_vblank,
+       .enable_vblank = i915gm_enable_vblank,
+       .disable_vblank = i915gm_disable_vblank,
 };
 
 static const struct drm_crtc_funcs i915_crtc_funcs = {
@@ -15136,8 +15136,8 @@ static int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe)
                        funcs = &g4x_crtc_funcs;
                else if (IS_GEN(dev_priv, 4))
                        funcs = &i965_crtc_funcs;
-               else if (IS_I945GM(dev_priv))
-                       funcs = &i945gm_crtc_funcs;
+               else if (IS_I945GM(dev_priv) || IS_I915GM(dev_priv))
+                       funcs = &i915gm_crtc_funcs;
                else if (IS_GEN(dev_priv, 3))
                        funcs = &i915_crtc_funcs;
                else
index 35b610d523790022253c8d18ef9bebab0ae04277..cde4c7fb5570c59770f17f9706e0192a7f588d78 100644 (file)
@@ -1701,13 +1701,8 @@ struct drm_i915_private {
                } contexts;
        } gem;
 
-       /* For i945gm vblank irq vs. C3 workaround */
-       struct {
-               struct work_struct work;
-               struct pm_qos_request pm_qos;
-               u8 c3_disable_latency;
-               u8 enabled;
-       } i945gm_vblank;
+       /* For i915gm/i945gm vblank irq workaround */
+       u8 vblank_enabled;
 
        /* perform PHY state sanity checks? */
        bool chv_phy_assert[2];
index bc83f094065ae0b4d3096842792ed75ebaabb232..f2371b6083c6d7852de83e46064f4d6b7f78d2ec 100644 (file)
@@ -29,7 +29,6 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/circ_buf.h>
-#include <linux/cpuidle.h>
 #include <linux/slab.h>
 #include <linux/sysrq.h>
 
@@ -2910,12 +2909,18 @@ int i8xx_enable_vblank(struct drm_crtc *crtc)
        return 0;
 }
 
-int i945gm_enable_vblank(struct drm_crtc *crtc)
+int i915gm_enable_vblank(struct drm_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = to_i915(crtc->dev);
 
-       if (dev_priv->i945gm_vblank.enabled++ == 0)
-               schedule_work(&dev_priv->i945gm_vblank.work);
+       /*
+        * Vblank interrupts fail to wake the device up from C2+.
+        * Disabling render clock gating during C-states avoids
+        * the problem. There is a small power cost so we do this
+        * only when vblank interrupts are actually enabled.
+        */
+       if (dev_priv->vblank_enabled++ == 0)
+               I915_WRITE(SCPD0, _MASKED_BIT_ENABLE(CSTATE_RENDER_CLOCK_GATE_DISABLE));
 
        return i8xx_enable_vblank(crtc);
 }
@@ -2988,14 +2993,14 @@ void i8xx_disable_vblank(struct drm_crtc *crtc)
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
-void i945gm_disable_vblank(struct drm_crtc *crtc)
+void i915gm_disable_vblank(struct drm_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = to_i915(crtc->dev);
 
        i8xx_disable_vblank(crtc);
 
-       if (--dev_priv->i945gm_vblank.enabled == 0)
-               schedule_work(&dev_priv->i945gm_vblank.work);
+       if (--dev_priv->vblank_enabled == 0)
+               I915_WRITE(SCPD0, _MASKED_BIT_DISABLE(CSTATE_RENDER_CLOCK_GATE_DISABLE));
 }
 
 void i965_disable_vblank(struct drm_crtc *crtc)
@@ -3034,60 +3039,6 @@ void bdw_disable_vblank(struct drm_crtc *crtc)
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
-static void i945gm_vblank_work_func(struct work_struct *work)
-{
-       struct drm_i915_private *dev_priv =
-               container_of(work, struct drm_i915_private, i945gm_vblank.work);
-
-       /*
-        * Vblank interrupts fail to wake up the device from C3,
-        * hence we want to prevent C3 usage while vblank interrupts
-        * are enabled.
-        */
-       pm_qos_update_request(&dev_priv->i945gm_vblank.pm_qos,
-                             READ_ONCE(dev_priv->i945gm_vblank.enabled) ?
-                             dev_priv->i945gm_vblank.c3_disable_latency :
-                             PM_QOS_DEFAULT_VALUE);
-}
-
-static int cstate_disable_latency(const char *name)
-{
-       const struct cpuidle_driver *drv;
-       int i;
-
-       drv = cpuidle_get_driver();
-       if (!drv)
-               return 0;
-
-       for (i = 0; i < drv->state_count; i++) {
-               const struct cpuidle_state *state = &drv->states[i];
-
-               if (!strcmp(state->name, name))
-                       return state->exit_latency ?
-                               state->exit_latency - 1 : 0;
-       }
-
-       return 0;
-}
-
-static void i945gm_vblank_work_init(struct drm_i915_private *dev_priv)
-{
-       INIT_WORK(&dev_priv->i945gm_vblank.work,
-                 i945gm_vblank_work_func);
-
-       dev_priv->i945gm_vblank.c3_disable_latency =
-               cstate_disable_latency("C3");
-       pm_qos_add_request(&dev_priv->i945gm_vblank.pm_qos,
-                          PM_QOS_CPU_DMA_LATENCY,
-                          PM_QOS_DEFAULT_VALUE);
-}
-
-static void i945gm_vblank_work_fini(struct drm_i915_private *dev_priv)
-{
-       cancel_work_sync(&dev_priv->i945gm_vblank.work);
-       pm_qos_remove_request(&dev_priv->i945gm_vblank.pm_qos);
-}
-
 static void ibx_irq_reset(struct drm_i915_private *dev_priv)
 {
        struct intel_uncore *uncore = &dev_priv->uncore;
@@ -4298,9 +4249,6 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
        struct intel_rps *rps = &dev_priv->gt_pm.rps;
        int i;
 
-       if (IS_I945GM(dev_priv))
-               i945gm_vblank_work_init(dev_priv);
-
        intel_hpd_init_work(dev_priv);
 
        INIT_WORK(&rps->work, gen6_pm_rps_work);
@@ -4388,9 +4336,6 @@ void intel_irq_fini(struct drm_i915_private *i915)
 {
        int i;
 
-       if (IS_I945GM(i915))
-               i945gm_vblank_work_fini(i915);
-
        for (i = 0; i < MAX_L3_SLICES; ++i)
                kfree(i915->l3_parity.remap_info[i]);
 }
index 8e7e6071777e3ced240c261ee6f28632d44f2bd1..19a3bc019535f082d69641b70695e7c622fab53d 100644 (file)
@@ -122,12 +122,12 @@ u32 i915_get_vblank_counter(struct drm_crtc *crtc);
 u32 g4x_get_vblank_counter(struct drm_crtc *crtc);
 
 int i8xx_enable_vblank(struct drm_crtc *crtc);
-int i945gm_enable_vblank(struct drm_crtc *crtc);
+int i915gm_enable_vblank(struct drm_crtc *crtc);
 int i965_enable_vblank(struct drm_crtc *crtc);
 int ilk_enable_vblank(struct drm_crtc *crtc);
 int bdw_enable_vblank(struct drm_crtc *crtc);
 void i8xx_disable_vblank(struct drm_crtc *crtc);
-void i945gm_disable_vblank(struct drm_crtc *crtc);
+void i915gm_disable_vblank(struct drm_crtc *crtc);
 void i965_disable_vblank(struct drm_crtc *crtc);
 void ilk_disable_vblank(struct drm_crtc *crtc);
 void bdw_disable_vblank(struct drm_crtc *crtc);
index 813ddea3f9f1fd83f999813f514cb053ff063096..6d67bd238cfe207c8bdc57889d8e6f3e67426684 100644 (file)
@@ -2709,6 +2709,7 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
 #define VLV_GU_CTL0    _MMIO(VLV_DISPLAY_BASE + 0x2030)
 #define VLV_GU_CTL1    _MMIO(VLV_DISPLAY_BASE + 0x2034)
 #define SCPD0          _MMIO(0x209c) /* 915+ only */
+#define  CSTATE_RENDER_CLOCK_GATE_DISABLE      (1 << 5)
 #define GEN2_IER       _MMIO(0x20a0)
 #define GEN2_IIR       _MMIO(0x20a4)
 #define GEN2_IMR       _MMIO(0x20a8)