From: Paulo Zanoni <[email protected]>

If we're already allowing PC8, just don't use the IRQs, so we won't
need to wake from PC8. Waking up from PC8 is a slow thing, so avoid it
when we can.

Signed-off-by: Paulo Zanoni <[email protected]>
---
 drivers/gpu/drm/i915/intel_i2c.c | 75 ++++++++++++++++++++++++++--------------
 1 file changed, 50 insertions(+), 25 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index d1c1e0f7..2f35c10 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -203,24 +203,18 @@ intel_gpio_setup(struct intel_gmbus *bus, u32 pin)
        algo->data = bus;
 }
 
-/*
- * gmbus on gen4 seems to be able to generate legacy interrupts even when in 
MSI
- * mode. This results in spurious interrupt warnings if the legacy irq no. is
- * shared with another device. The kernel then disables that interrupt source
- * and so prevents the other device from working properly.
- */
-#define HAS_GMBUS_IRQ(dev) (INTEL_INFO(dev)->gen >= 5)
 static int
 gmbus_wait_hw_status(struct drm_i915_private *dev_priv,
                     u32 gmbus2_status,
-                    u32 gmbus4_irq_en)
+                    u32 gmbus4_irq_en,
+                    bool use_irq)
 {
        int i;
        int reg_offset = dev_priv->gpio_mmio_base;
        u32 gmbus2 = 0;
        DEFINE_WAIT(wait);
 
-       if (!HAS_GMBUS_IRQ(dev_priv->dev))
+       if (!use_irq)
                gmbus4_irq_en = 0;
 
        /* Important: The hw handles only the first bit, so set only one! Since
@@ -250,14 +244,14 @@ gmbus_wait_hw_status(struct drm_i915_private *dev_priv,
 }
 
 static int
-gmbus_wait_idle(struct drm_i915_private *dev_priv)
+gmbus_wait_idle(struct drm_i915_private *dev_priv, bool use_irq)
 {
        int ret;
        int reg_offset = dev_priv->gpio_mmio_base;
 
 #define C ((I915_READ_NOTRACE(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0)
 
-       if (!HAS_GMBUS_IRQ(dev_priv->dev))
+       if (!use_irq)
                return wait_for(C, 10);
 
        /* Important: The hw handles only the first bit, so set only one! */
@@ -277,7 +271,7 @@ gmbus_wait_idle(struct drm_i915_private *dev_priv)
 
 static int
 gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
-               u32 gmbus1_index)
+               u32 gmbus1_index, bool use_irq)
 {
        int reg_offset = dev_priv->gpio_mmio_base;
        u16 len = msg->len;
@@ -294,7 +288,7 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct 
i2c_msg *msg,
                u32 val, loop = 0;
 
                ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY,
-                                          GMBUS_HW_RDY_EN);
+                                          GMBUS_HW_RDY_EN, use_irq);
                if (ret)
                        return ret;
 
@@ -309,7 +303,8 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct 
i2c_msg *msg,
 }
 
 static int
-gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)
+gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
+                bool use_irq)
 {
        int reg_offset = dev_priv->gpio_mmio_base;
        u16 len = msg->len;
@@ -339,7 +334,7 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct 
i2c_msg *msg)
                I915_WRITE(GMBUS3 + reg_offset, val);
 
                ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY,
-                                          GMBUS_HW_RDY_EN);
+                                          GMBUS_HW_RDY_EN, use_irq);
                if (ret)
                        return ret;
        }
@@ -359,7 +354,8 @@ gmbus_is_index_read(struct i2c_msg *msgs, int i, int num)
 }
 
 static int
-gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs)
+gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs,
+                     bool use_irq)
 {
        int reg_offset = dev_priv->gpio_mmio_base;
        u32 gmbus1_index = 0;
@@ -377,7 +373,7 @@ gmbus_xfer_index_read(struct drm_i915_private *dev_priv, 
struct i2c_msg *msgs)
        if (gmbus5)
                I915_WRITE(GMBUS5 + reg_offset, gmbus5);
 
-       ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus1_index);
+       ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus1_index, use_irq);
 
        /* Clear GMBUS5 after each index transfer */
        if (gmbus5)
@@ -386,6 +382,31 @@ gmbus_xfer_index_read(struct drm_i915_private *dev_priv, 
struct i2c_msg *msgs)
        return ret;
 }
 
+static bool gmbus_use_irq(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       bool ret;
+
+       /*
+        * gmbus on gen4 seems to be able to generate legacy interrupts even
+        * when in MSI mode. This results in spurious interrupt warnings if the
+        * legacy irq no. is shared with another device. The kernel then
+        * disables that interrupt source and so prevents the other device from
+        * working properly.
+        */
+       if (INTEL_INFO(dev)->gen <= 4)
+               return false;
+
+       /* In case we're already allowing PC8, just don't use IRQs, so we won't
+        * need to call intel_aux_display_runtime_get and then we won't wake up
+        * from PC8. */
+       mutex_lock(&dev_priv->pc8.lock);
+       ret = (dev_priv->pc8.forbid_refcnt != 0);
+       mutex_unlock(&dev_priv->pc8.lock);
+
+       return ret;
+}
+
 static int
 gmbus_xfer(struct i2c_adapter *adapter,
           struct i2c_msg *msgs,
@@ -397,8 +418,10 @@ gmbus_xfer(struct i2c_adapter *adapter,
        struct drm_i915_private *dev_priv = bus->dev_priv;
        int i, reg_offset;
        int ret = 0;
+       bool use_irq = gmbus_use_irq(dev_priv->dev);
 
-       intel_aux_display_runtime_get(dev_priv);
+       if (use_irq)
+               intel_aux_display_runtime_get(dev_priv);
        mutex_lock(&dev_priv->gmbus_mutex);
 
        if (bus->force_bit) {
@@ -412,12 +435,13 @@ gmbus_xfer(struct i2c_adapter *adapter,
 
        for (i = 0; i < num; i++) {
                if (gmbus_is_index_read(msgs, i, num)) {
-                       ret = gmbus_xfer_index_read(dev_priv, &msgs[i]);
+                       ret = gmbus_xfer_index_read(dev_priv, &msgs[i],
+                                                   use_irq);
                        i += 1;  /* set i to the index of the read xfer */
                } else if (msgs[i].flags & I2C_M_RD) {
-                       ret = gmbus_xfer_read(dev_priv, &msgs[i], 0);
+                       ret = gmbus_xfer_read(dev_priv, &msgs[i], 0, use_irq);
                } else {
-                       ret = gmbus_xfer_write(dev_priv, &msgs[i]);
+                       ret = gmbus_xfer_write(dev_priv, &msgs[i], use_irq);
                }
 
                if (ret == -ETIMEDOUT)
@@ -426,7 +450,7 @@ gmbus_xfer(struct i2c_adapter *adapter,
                        goto clear_err;
 
                ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_WAIT_PHASE,
-                                          GMBUS_HW_WAIT_EN);
+                                          GMBUS_HW_WAIT_EN, use_irq);
                if (ret == -ENXIO)
                        goto clear_err;
                if (ret)
@@ -443,7 +467,7 @@ gmbus_xfer(struct i2c_adapter *adapter,
         * We will re-enable it at the start of the next xfer,
         * till then let it sleep.
         */
-       if (gmbus_wait_idle(dev_priv)) {
+       if (gmbus_wait_idle(dev_priv, use_irq)) {
                DRM_DEBUG_KMS("GMBUS [%s] timed out waiting for idle\n",
                         adapter->name);
                ret = -ETIMEDOUT;
@@ -467,7 +491,7 @@ clear_err:
         * it's slow responding and only answers on the 2nd retry.
         */
        ret = -ENXIO;
-       if (gmbus_wait_idle(dev_priv)) {
+       if (gmbus_wait_idle(dev_priv, use_irq)) {
                DRM_DEBUG_KMS("GMBUS [%s] timed out after NAK\n",
                              adapter->name);
                ret = -ETIMEDOUT;
@@ -498,7 +522,8 @@ timeout:
 
 out:
        mutex_unlock(&dev_priv->gmbus_mutex);
-       intel_aux_display_runtime_put(dev_priv);
+       if (use_irq)
+               intel_aux_display_runtime_put(dev_priv);
        return ret;
 }
 
-- 
1.8.1.2

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to