From patchwork Thu Sep 6 13:44:33 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Vetter X-Patchwork-Id: 1415241 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by patchwork1.kernel.org (Postfix) with ESMTP id 8244B3FC71 for ; Thu, 6 Sep 2012 14:52:24 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 756B69F6C4 for ; Thu, 6 Sep 2012 07:52:24 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mail-wg0-f43.google.com (mail-wg0-f43.google.com [74.125.82.43]) by gabe.freedesktop.org (Postfix) with ESMTP id 08F1C9F6C4 for ; Thu, 6 Sep 2012 07:51:55 -0700 (PDT) Received: by wgbdr1 with SMTP id dr1so1211478wgb.12 for ; Thu, 06 Sep 2012 07:51:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ffwll.ch; s=google; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=FNqOAa86jmYcZgwdd0QdmRLf1XsFZo+mtuP7Zw4y/Ko=; b=CpqIm0UPabRXvIA/odVJ8qIjaFvDLrWuiPnWbjP4TDtzZQgojBaJVXOHbyE3PCinMD 1ZPixDvIwzJXXeipvBhSI59i5ck4M//DyecVA+Gj3HRhG/i5eOE49vZIVnFrUQqAacZK u70rgWrgoGlsddD2ppnWFnNcP3N9Umbk/JvNI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references :x-gm-message-state; bh=FNqOAa86jmYcZgwdd0QdmRLf1XsFZo+mtuP7Zw4y/Ko=; b=XjHzVkbdEzAUqLxg789Us4PJiJh4uOy4yJguRRwv0bT1fMvfY4CPSpFJMZ1rpVAabu LyjPDSRyyrHhgsoH7xIid95/BQZPRdzmU9IEGmmtGV3ygwkF8T6sOabJkUonwd21PrI2 isWTMGaVfrNKCWmAgi6o/vZqN3QlPWYJX6zOx3ejJ1A47mUWN5XvCnLtXeiwpM27FpD2 QsxL7Qnnf4pQQcXRxXWqmSW5wd6jsSRuMw1gxCdahB6TS9DYfyIjHycg43H4Oxp7ibKz 6D3PqftI9ZmNEOaS0U2vR4opKtLKCtbLoDsrchAzwoZzd8vV8twL/kNL5T3TwuEnbmQ5 Gs3Q== Received: by 10.180.106.97 with SMTP id gt1mr46339229wib.5.1346943114881; Thu, 06 Sep 2012 07:51:54 -0700 (PDT) Received: from wespe.ffwll.local (178-83-130-250.dynamic.hispeed.ch. [178.83.130.250]) by mx.google.com with ESMTPS id ef5sm6308614wib.3.2012.09.06.07.51.52 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 06 Sep 2012 07:51:53 -0700 (PDT) From: Daniel Vetter To: Intel Graphics Development Date: Thu, 6 Sep 2012 15:44:33 +0200 Message-Id: <1346939073-5965-1-git-send-email-daniel.vetter@ffwll.ch> X-Mailer: git-send-email 1.7.11.2 In-Reply-To: <6c3329$5soj8t@orsmga002.jf.intel.com> References: <6c3329$5soj8t@orsmga002.jf.intel.com> X-Gm-Message-State: ALoCoQmn/PD4FZCg9uuEDIHHPLrYNnfmQL2dguKjsNDSSbC9dwYOSf0zJpmgcZbicrfNvaJiINU1 Cc: Daniel Vetter Subject: [Intel-gfx] [PATCH] drm/i915: use the gmbus irq for waits X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: intel-gfx-bounces+patchwork-intel-gfx=patchwork.kernel.org@lists.freedesktop.org Errors-To: intel-gfx-bounces+patchwork-intel-gfx=patchwork.kernel.org@lists.freedesktop.org We need two special things to properly wire this up: - Add another argument to gmbus_wait_hw_status to pass in the correct interrupt bit in gmbus4. - Since we can only get an irq for one of the two events we want, hand-roll the wait_event_timeout code so that we wake up every jiffie and can check for NAKs. This way we also subsume gmbus support for platforms without interrupts (or where those are not yet enabled). The important bit really is to only enable one gmbus interrupt source at the same time - with that piece of lore figured out, this seems to work flawlessly. Ben Widawsky rightfully complained the lack of measurements for the claimed benefits (especially since the first version was actually broken and fell back to bit-banging). Previously reading the 256 byte hdmi EDID takes about 72 ms here. With this patch it's down to 33 ms. Given that transfering the 256 bytes over i2c at wire speed takes 20.5ms alone, the reduction in additional overhead is rather nice. v2: Chris Wilson wondered whether GMBUS4 might contain some set bits when booting up an hence result in some spurious interrupts. Since we clear GMBUS4 after every wait and we do gmbus transfer really early in the setup sequence to detect displays the window is small, but still be paranoid and clear it properly. v3: Clarify the comment that gmbus irq generation can only support one kind of event, why it bothers us and how we work around that limit. Cc: Daniel Kurtz Signed-off-by: Daniel Vetter fixup --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_irq.c | 4 ++++ drivers/gpu/drm/i915/intel_i2c.c | 45 ++++++++++++++++++++++++++++++---------- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5c8d5e3..72db70d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -418,6 +418,8 @@ typedef struct drm_i915_private { */ uint32_t gpio_mmio_base; + wait_queue_head_t gmbus_wait_queue; + struct pci_dev *bridge_dev; struct intel_ring_buffer ring[I915_NUM_RINGS]; uint32_t next_seqno; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 8415fa6..dadc86b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -598,7 +598,11 @@ out: static void gmbus_irq_handler(struct drm_device *dev) { + struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private; + DRM_DEBUG_DRIVER("GMBUS interrupt\n"); + + wake_up_all(&dev_priv->gmbus_wait_queue); } static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 57decac..7413595 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -64,6 +64,7 @@ intel_i2c_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; I915_WRITE(dev_priv->gpio_mmio_base + GMBUS0, 0); + I915_WRITE(dev_priv->gpio_mmio_base + GMBUS4, 0); } static void intel_i2c_quirk_set(struct drm_i915_private *dev_priv, bool enable) @@ -205,20 +206,38 @@ intel_gpio_setup(struct intel_gmbus *bus, u32 pin) static int gmbus_wait_hw_status(struct drm_i915_private *dev_priv, - u32 gmbus2_status) + u32 gmbus2_status, + u32 gmbus4_irq_en) { - int ret; + int i; int reg_offset = dev_priv->gpio_mmio_base; - u32 gmbus2; + u32 gmbus2 = 0; + DEFINE_WAIT(wait); + + /* Important: The hw handles only the first bit, so set only one! Since + * we also need to check for NAKs besides the hw ready/idle signal, we + * need to wake up periodically and check that ourselves. */ + I915_WRITE(GMBUS4 + reg_offset, gmbus4_irq_en); - ret = wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) & - (GMBUS_SATOER | gmbus2_status), - 50); + for (i = 0; i < msecs_to_jiffies(50) + 1; i++) { + prepare_to_wait(&dev_priv->gmbus_wait_queue, &wait, + TASK_UNINTERRUPTIBLE); + + gmbus2 = I915_READ(GMBUS2 + reg_offset); + if (gmbus2 & (GMBUS_SATOER | gmbus2_status)) + break; + + schedule_timeout(1); + } + finish_wait(&dev_priv->gmbus_wait_queue, &wait); + + I915_WRITE(GMBUS4 + reg_offset, 0); if (gmbus2 & GMBUS_SATOER) return -ENXIO; - - return ret; + if (gmbus2 & gmbus2_status) + return 0; + return -ETIMEDOUT; } static int @@ -239,7 +258,8 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, int ret; u32 val, loop = 0; - ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY); + ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY, + GMBUS_HW_RDY_EN); if (ret) return ret; @@ -283,7 +303,8 @@ 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); + ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY, + GMBUS_HW_RDY_EN); if (ret) return ret; } @@ -368,7 +389,8 @@ gmbus_xfer(struct i2c_adapter *adapter, if (ret == -ENXIO) goto clear_err; - ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_WAIT_PHASE); + ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_WAIT_PHASE, + GMBUS_HW_WAIT_EN); if (ret == -ENXIO) goto clear_err; if (ret) @@ -474,6 +496,7 @@ int intel_setup_gmbus(struct drm_device *dev) dev_priv->gpio_mmio_base = 0; mutex_init(&dev_priv->gmbus_mutex); + init_waitqueue_head(&dev_priv->gmbus_wait_queue); for (i = 0; i < GMBUS_NUM_PORTS; i++) { struct intel_gmbus *bus = &dev_priv->gmbus[i];