On Sat, May 16, 2015 at 09:37:11AM +0200, Jiri Slaby wrote: > From: Dmitry Torokhov <dmitry.torokhov@xxxxxxxxx> > > 3.12-stable review patch. If anyone has any objections, please let me know. > Ben Hutchings (on CC) just asked about this patch being included on the 3.16 kernel [1]. Is this patch really useful for kernels < 3.17? Should it be reverted from all the other stable kernels (3.10, 3.14 and 3.16), or do you think it's harmless? [1] http://thread.gmane.org/gmane.linux.kernel.stable/136673 Cheers, -- Luís > =============== > > commit 9535c4757b881e06fae72a857485ad57c422b8d2 upstream. > > The hardware, according to the specs, is limited to 256 byte 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). > > Reviewed-by: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> > Signed-off-by: Dmitry Torokhov <dmitry.torokhov@xxxxxxxxx> > Signed-off-by: Jani Nikula <jani.nikula@xxxxxxxxx> > Signed-off-by: Jiri Slaby <jslaby@xxxxxxx> > --- > drivers/gpu/drm/i915/i915_reg.h | 1 + > drivers/gpu/drm/i915/intel_i2c.c | 66 ++++++++++++++++++++++++++++++++++------ > 2 files changed, 57 insertions(+), 10 deletions(-) > > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h > index 9d344da55056..4e0053e64f14 100644 > --- a/drivers/gpu/drm/i915/i915_reg.h > +++ b/drivers/gpu/drm/i915/i915_reg.h > @@ -1105,6 +1105,7 @@ > #define GMBUS_CYCLE_INDEX (2<<25) > #define GMBUS_CYCLE_STOP (4<<25) > #define GMBUS_BYTE_COUNT_SHIFT 16 > +#define GMBUS_BYTE_COUNT_MAX 256U > #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 d1c1e0f7f262..36b720475dc0 100644 > --- a/drivers/gpu/drm/i915/intel_i2c.c > +++ b/drivers/gpu/drm/i915/intel_i2c.c > @@ -276,18 +276,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; > @@ -309,11 +308,35 @@ 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; > @@ -325,8 +348,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; > @@ -343,6 +366,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; > } > > -- > 2.3.7 > > -- > To unsubscribe from this list: send the line "unsubscribe stable" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe stable" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html