From patchwork Mon Apr 20 22:11:16 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Torokhov X-Patchwork-Id: 6244641 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id E2036BF4A6 for ; Mon, 20 Apr 2015 22:36:05 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id CA78F202E6 for ; Mon, 20 Apr 2015 22:36:04 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id D9482202B8 for ; Mon, 20 Apr 2015 22:36:03 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 8FEA96E53E; Mon, 20 Apr 2015 15:36:02 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mail-ie0-f176.google.com (mail-ie0-f176.google.com [209.85.223.176]) by gabe.freedesktop.org (Postfix) with ESMTP id EF1566E507; Mon, 20 Apr 2015 15:11:20 -0700 (PDT) Received: by iecrt8 with SMTP id rt8so559989iec.0; Mon, 20 Apr 2015 15:11:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=date:from:to:cc:subject:message-id:mime-version:content-type :content-disposition:user-agent; bh=p7QX/nD7FfWtV5axFrhyhTz/eQsHBTjNt6uNf3wM4C0=; b=r3RvGtIcXqDFOSy55qNcB/OAPuzxbYA+P+6YW/W8DFnxA1aqAq5LmdTCGG6zhvT44A vfPyx9r6p/aUGlUaLz3oELF+wrDjnlfOsg3MLlL/66v2yr7Ys8Lh5m78VZZiB8SZvJ4z lLcC3SwaYlsPY4t3OidQOClXiKuLRb9zuo9/VGz9cycPfrfSk5JBwFHn7OX5yhutLqnL wowY+ALO6TbRdnbJoOCC9XPBWmT9rMC8RiS5iAycUZoPMG8xTiRTYvwoPtLnURK+5R5p ocyUm10ngPFON5k4o4XXBNzGLizWylF7SAgunEhe/2bs+N4wkRqZCPvkLC+zhwJDgn6B 28MQ== X-Received: by 10.43.156.6 with SMTP id lk6mr32795icc.44.1429567880608; Mon, 20 Apr 2015 15:11:20 -0700 (PDT) Received: from dtor-ws ([2620:0:1000:1301:b4a4:15d2:d9fe:1711]) by mx.google.com with ESMTPSA id j39sm9297078iod.41.2015.04.20.15.11.18 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Mon, 20 Apr 2015 15:11:19 -0700 (PDT) Date: Mon, 20 Apr 2015 15:11:16 -0700 From: Dmitry Torokhov To: David Airlie Message-ID: <20150420221116.GA1261@dtor-ws> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) X-Mailman-Approved-At: Mon, 20 Apr 2015 15:36:01 -0700 Cc: dri-devel@lists.freedesktop.org, intel-gfx@lists.freedesktop.org, linux-kernel@vger.kernel.org, Nick Dyer , Olof Johansson , Daniel Vetter , Linus Torvalds Subject: [Intel-gfx] [PATCH] drm/i915: cope with large i2c transfers X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_MED, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The hardware is limited to 2^9 - 1 (511) bytes transfers, and current driver has no protections in case users attempt to do larger transfers. The code will just stomp over status register and mayhem ensues. Let's split larger transfers into digestable chunks. Doing this allows Atmel MXT driver on Pixel 1 function properly (it hasn't since commit 9d8dc3e529a19e427fd379118acd132520935c5d "Input: atmel_mxt_ts - implement T44 message handling" which tries to consume multiple touchscreen/touchpad reports in a single transaction). Signed-off-by: Dmitry Torokhov Reviewed-by: Chris Wilson --- I think I've tracked the main reason for the Pixel Touchpad breakage on newer kernels. The newer driver tries to consume several reports form touchscreen, and tries to read ~600 bytes at startup. i915 does not check the message limits and messes up GMBUS register, causing "phantom" reads on another i2c channel where the touchpad is connected. With i915 splitting the data into smaller chunks for transfer my Pixel reliably detects both touchpad and touchscreen on 4.0. Might be worth considering for stable too... Thanks, Dmitry drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_i2c.c | 67 ++++++++++++++++++++++++++++++++++------ 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b522eb6..dc45dbf 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1807,6 +1807,7 @@ enum skl_disp_power_wells { #define GMBUS_CYCLE_INDEX (2<<25) #define GMBUS_CYCLE_STOP (4<<25) #define GMBUS_BYTE_COUNT_SHIFT 16 +#define GMBUS_BYTE_COUNT_MAX ((1U << 9) - 1) #define GMBUS_SLAVE_INDEX_SHIFT 8 #define GMBUS_SLAVE_ADDR_SHIFT 1 #define GMBUS_SLAVE_READ (1<<0) diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index b31088a..1c3b4ae 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -270,18 +270,17 @@ 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) +gmbus_xfer_read_chunk(struct drm_i915_private *dev_priv, + unsigned short addr, u8 *buf, unsigned int len, + u32 gmbus1_index) { int reg_offset = dev_priv->gpio_mmio_base; - u16 len = msg->len; - u8 *buf = msg->buf; I915_WRITE(GMBUS1 + reg_offset, gmbus1_index | GMBUS_CYCLE_WAIT | (len << GMBUS_BYTE_COUNT_SHIFT) | - (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) | + (addr << GMBUS_SLAVE_ADDR_SHIFT) | GMBUS_SLAVE_READ | GMBUS_SW_RDY); while (len) { int ret; @@ -303,11 +302,36 @@ 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_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, + u32 gmbus1_index) { - int reg_offset = dev_priv->gpio_mmio_base; - u16 len = msg->len; u8 *buf = msg->buf; + unsigned int rx_size = msg->len; + unsigned int len; + int ret; + + do { + len = min(rx_size, GMBUS_BYTE_COUNT_MAX); + + ret = gmbus_xfer_read_chunk(dev_priv, msg->addr, + buf, len, gmbus1_index); + if (ret) + return ret; + + rx_size -= len; + buf += len; + } while (rx_size != 0); + + return 0; +} + + +static int +gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv, + unsigned short addr, u8 *buf, unsigned int len) +{ + int reg_offset = dev_priv->gpio_mmio_base; + unsigned int chunk_size = len; u32 val, loop; val = loop = 0; @@ -319,8 +343,8 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) I915_WRITE(GMBUS3 + reg_offset, val); I915_WRITE(GMBUS1 + reg_offset, GMBUS_CYCLE_WAIT | - (msg->len << GMBUS_BYTE_COUNT_SHIFT) | - (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) | + (chunk_size << GMBUS_BYTE_COUNT_SHIFT) | + (addr << GMBUS_SLAVE_ADDR_SHIFT) | GMBUS_SLAVE_WRITE | GMBUS_SW_RDY); while (len) { int ret; @@ -337,6 +361,29 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) if (ret) return ret; } + + return 0; +} + +static int +gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) +{ + u8 *buf = msg->buf; + unsigned int tx_size = msg->len; + unsigned int len; + int ret; + + do { + len = min(tx_size, GMBUS_BYTE_COUNT_MAX); + + ret = gmbus_xfer_write_chunk(dev_priv, msg->addr, buf, len); + if (ret) + return ret; + + buf += len; + tx_size -= len; + } while (tx_size != 0); + return 0; }