aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2015-04-21 12:49:11 -0400
committerJani Nikula <jani.nikula@intel.com>2015-04-23 16:48:18 -0400
commit9535c4757b881e06fae72a857485ad57c422b8d2 (patch)
tree6362a8d89171fba94539c0475d6b2ccb2ea9e7f2
parent37ef01ab5d24d1d520dc79f6a98099d451c2a901 (diff)
drm/i915: cope with large i2c transfers
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). Cc: stable@vger.kernel.org Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com>
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h1
-rw-r--r--drivers/gpu/drm/i915/intel_i2c.c66
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 b522eb6e59a4..3da1af46625c 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 {
1807#define GMBUS_CYCLE_INDEX (2<<25) 1807#define GMBUS_CYCLE_INDEX (2<<25)
1808#define GMBUS_CYCLE_STOP (4<<25) 1808#define GMBUS_CYCLE_STOP (4<<25)
1809#define GMBUS_BYTE_COUNT_SHIFT 16 1809#define GMBUS_BYTE_COUNT_SHIFT 16
1810#define GMBUS_BYTE_COUNT_MAX 256U
1810#define GMBUS_SLAVE_INDEX_SHIFT 8 1811#define GMBUS_SLAVE_INDEX_SHIFT 8
1811#define GMBUS_SLAVE_ADDR_SHIFT 1 1812#define GMBUS_SLAVE_ADDR_SHIFT 1
1812#define GMBUS_SLAVE_READ (1<<0) 1813#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 b31088a551f2..56e437e31580 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)
270} 270}
271 271
272static int 272static int
273gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, 273gmbus_xfer_read_chunk(struct drm_i915_private *dev_priv,
274 u32 gmbus1_index) 274 unsigned short addr, u8 *buf, unsigned int len,
275 u32 gmbus1_index)
275{ 276{
276 int reg_offset = dev_priv->gpio_mmio_base; 277 int reg_offset = dev_priv->gpio_mmio_base;
277 u16 len = msg->len;
278 u8 *buf = msg->buf;
279 278
280 I915_WRITE(GMBUS1 + reg_offset, 279 I915_WRITE(GMBUS1 + reg_offset,
281 gmbus1_index | 280 gmbus1_index |
282 GMBUS_CYCLE_WAIT | 281 GMBUS_CYCLE_WAIT |
283 (len << GMBUS_BYTE_COUNT_SHIFT) | 282 (len << GMBUS_BYTE_COUNT_SHIFT) |
284 (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) | 283 (addr << GMBUS_SLAVE_ADDR_SHIFT) |
285 GMBUS_SLAVE_READ | GMBUS_SW_RDY); 284 GMBUS_SLAVE_READ | GMBUS_SW_RDY);
286 while (len) { 285 while (len) {
287 int ret; 286 int ret;
@@ -303,11 +302,35 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
303} 302}
304 303
305static int 304static int
306gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) 305gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
306 u32 gmbus1_index)
307{ 307{
308 int reg_offset = dev_priv->gpio_mmio_base;
309 u16 len = msg->len;
310 u8 *buf = msg->buf; 308 u8 *buf = msg->buf;
309 unsigned int rx_size = msg->len;
310 unsigned int len;
311 int ret;
312
313 do {
314 len = min(rx_size, GMBUS_BYTE_COUNT_MAX);
315
316 ret = gmbus_xfer_read_chunk(dev_priv, msg->addr,
317 buf, len, gmbus1_index);
318 if (ret)
319 return ret;
320
321 rx_size -= len;
322 buf += len;
323 } while (rx_size != 0);
324
325 return 0;
326}
327
328static int
329gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
330 unsigned short addr, u8 *buf, unsigned int len)
331{
332 int reg_offset = dev_priv->gpio_mmio_base;
333 unsigned int chunk_size = len;
311 u32 val, loop; 334 u32 val, loop;
312 335
313 val = loop = 0; 336 val = loop = 0;
@@ -319,8 +342,8 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)
319 I915_WRITE(GMBUS3 + reg_offset, val); 342 I915_WRITE(GMBUS3 + reg_offset, val);
320 I915_WRITE(GMBUS1 + reg_offset, 343 I915_WRITE(GMBUS1 + reg_offset,
321 GMBUS_CYCLE_WAIT | 344 GMBUS_CYCLE_WAIT |
322 (msg->len << GMBUS_BYTE_COUNT_SHIFT) | 345 (chunk_size << GMBUS_BYTE_COUNT_SHIFT) |
323 (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) | 346 (addr << GMBUS_SLAVE_ADDR_SHIFT) |
324 GMBUS_SLAVE_WRITE | GMBUS_SW_RDY); 347 GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
325 while (len) { 348 while (len) {
326 int ret; 349 int ret;
@@ -337,6 +360,29 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)
337 if (ret) 360 if (ret)
338 return ret; 361 return ret;
339 } 362 }
363
364 return 0;
365}
366
367static int
368gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)
369{
370 u8 *buf = msg->buf;
371 unsigned int tx_size = msg->len;
372 unsigned int len;
373 int ret;
374
375 do {
376 len = min(tx_size, GMBUS_BYTE_COUNT_MAX);
377
378 ret = gmbus_xfer_write_chunk(dev_priv, msg->addr, buf, len);
379 if (ret)
380 return ret;
381
382 buf += len;
383 tx_size -= len;
384 } while (tx_size != 0);
385
340 return 0; 386 return 0;
341} 387}
342 388