From: Paulo Zanoni <paulo.r.zanoni@xxxxxxxxx> 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 <paulo.r.zanoni@xxxxxxxxx> --- 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 Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx