aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorPeter Swain <pswain@cavium.com>2016-04-25 10:33:37 -0400
committerWolfram Sang <wsa@the-dreams.de>2016-04-26 17:19:40 -0400
commit1bb1ff3e7c74f4569dddf7bda8054a0bb6ed0073 (patch)
tree12265caac255409a81c8b2d36df39d7826f6d7b0 /drivers/i2c
parent392d01de2d2476e8a50cf30f049e369deaaea127 (diff)
i2c: octeon: Improve performance if interrupt is early
There is a race between the TWSI interrupt and the condition that is required before proceeding: Low-level: interrupt flag bit must be set High-level controller: valid bit must be clear If the interrupt comes too early and the condition is not met the wait will time out, and the transfer is aborted leading to very poor performance. To avoid this race retry for the condition ~80 µs later. The retry is avoided on the very first invocation of wait_event_timeout() (which tests the condition before entering the wait and is therefore always wrong in this case). EEPROM reads on 100kHz i2c now measure ~5.2kB/s, about 1/2 what's achievable, and much better than the worst-case 100 bytes/sec before. While at it remove the debug print from the low-level wait function. Signed-off-by: Peter Swain <pswain@cavium.com> Signed-off-by: Jan Glauber <jglauber@cavium.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-octeon.c55
1 files changed, 46 insertions, 9 deletions
diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index 4fc471ce173e..cb418140cbbe 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -109,6 +109,8 @@
109#define TWSI_INT_SDA BIT_ULL(10) 109#define TWSI_INT_SDA BIT_ULL(10)
110#define TWSI_INT_SCL BIT_ULL(11) 110#define TWSI_INT_SCL BIT_ULL(11)
111 111
112#define I2C_OCTEON_EVENT_WAIT 80 /* microseconds */
113
112struct octeon_i2c { 114struct octeon_i2c {
113 wait_queue_head_t queue; 115 wait_queue_head_t queue;
114 struct i2c_adapter adap; 116 struct i2c_adapter adap;
@@ -339,11 +341,29 @@ static irqreturn_t octeon_i2c_hlc_isr78(int irq, void *dev_id)
339 return IRQ_HANDLED; 341 return IRQ_HANDLED;
340} 342}
341 343
342static int octeon_i2c_test_iflg(struct octeon_i2c *i2c) 344static bool octeon_i2c_test_iflg(struct octeon_i2c *i2c)
343{ 345{
344 return (octeon_i2c_ctl_read(i2c) & TWSI_CTL_IFLG); 346 return (octeon_i2c_ctl_read(i2c) & TWSI_CTL_IFLG);
345} 347}
346 348
349static bool octeon_i2c_test_ready(struct octeon_i2c *i2c, bool *first)
350{
351 if (octeon_i2c_test_iflg(i2c))
352 return true;
353
354 if (*first) {
355 *first = false;
356 return false;
357 }
358
359 /*
360 * IRQ has signaled an event but IFLG hasn't changed.
361 * Sleep and retry once.
362 */
363 usleep_range(I2C_OCTEON_EVENT_WAIT, 2 * I2C_OCTEON_EVENT_WAIT);
364 return octeon_i2c_test_iflg(i2c);
365}
366
347/** 367/**
348 * octeon_i2c_wait - wait for the IFLG to be set 368 * octeon_i2c_wait - wait for the IFLG to be set
349 * @i2c: The struct octeon_i2c 369 * @i2c: The struct octeon_i2c
@@ -353,15 +373,14 @@ static int octeon_i2c_test_iflg(struct octeon_i2c *i2c)
353static int octeon_i2c_wait(struct octeon_i2c *i2c) 373static int octeon_i2c_wait(struct octeon_i2c *i2c)
354{ 374{
355 long time_left; 375 long time_left;
376 bool first = 1;
356 377
357 i2c->int_enable(i2c); 378 i2c->int_enable(i2c);
358 time_left = wait_event_timeout(i2c->queue, octeon_i2c_test_iflg(i2c), 379 time_left = wait_event_timeout(i2c->queue, octeon_i2c_test_ready(i2c, &first),
359 i2c->adap.timeout); 380 i2c->adap.timeout);
360 i2c->int_disable(i2c); 381 i2c->int_disable(i2c);
361 if (!time_left) { 382 if (!time_left)
362 dev_dbg(i2c->dev, "%s: timeout\n", __func__);
363 return -ETIMEDOUT; 383 return -ETIMEDOUT;
364 }
365 384
366 return 0; 385 return 0;
367} 386}
@@ -427,11 +446,28 @@ static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read)
427 } 446 }
428} 447}
429 448
430static bool octeon_i2c_hlc_test_ready(struct octeon_i2c *i2c) 449static bool octeon_i2c_hlc_test_valid(struct octeon_i2c *i2c)
450{
451 return (__raw_readq(i2c->twsi_base + SW_TWSI) & SW_TWSI_V) == 0;
452}
453
454static bool octeon_i2c_hlc_test_ready(struct octeon_i2c *i2c, bool *first)
431{ 455{
432 u64 val = __raw_readq(i2c->twsi_base + SW_TWSI); 456 /* check if valid bit is cleared */
457 if (octeon_i2c_hlc_test_valid(i2c))
458 return true;
433 459
434 return (val & SW_TWSI_V) == 0; 460 if (*first) {
461 *first = false;
462 return false;
463 }
464
465 /*
466 * IRQ has signaled an event but valid bit isn't cleared.
467 * Sleep and retry once.
468 */
469 usleep_range(I2C_OCTEON_EVENT_WAIT, 2 * I2C_OCTEON_EVENT_WAIT);
470 return octeon_i2c_hlc_test_valid(i2c);
435} 471}
436 472
437static void octeon_i2c_hlc_int_enable(struct octeon_i2c *i2c) 473static void octeon_i2c_hlc_int_enable(struct octeon_i2c *i2c)
@@ -453,11 +489,12 @@ static void octeon_i2c_hlc_int_clear(struct octeon_i2c *i2c)
453 */ 489 */
454static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c) 490static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c)
455{ 491{
492 bool first = 1;
456 int time_left; 493 int time_left;
457 494
458 i2c->hlc_int_enable(i2c); 495 i2c->hlc_int_enable(i2c);
459 time_left = wait_event_timeout(i2c->queue, 496 time_left = wait_event_timeout(i2c->queue,
460 octeon_i2c_hlc_test_ready(i2c), 497 octeon_i2c_hlc_test_ready(i2c, &first),
461 i2c->adap.timeout); 498 i2c->adap.timeout);
462 i2c->hlc_int_disable(i2c); 499 i2c->hlc_int_disable(i2c);
463 if (!time_left) { 500 if (!time_left) {