* [PATCH 1/4] i2c-bfin-twi: work around illegal i2c bus lock with long transfers
@ 2011-05-25 20:26 Mike Frysinger
[not found] ` <1306355198-18530-1-git-send-email-vapier-aBrp7R+bbdUdnm+yROfE0A@public.gmane.org>
0 siblings, 1 reply; 4+ messages in thread
From: Mike Frysinger @ 2011-05-25 20:26 UTC (permalink / raw)
To: linux-i2c-u79uwXL29TY76Z2rM5mHXA, Ben Dooks
Cc: uclinux-dist-devel-ZG0+EudsQA8dtHy/vicBwGD2FQJk+8+b,
Michael Hennerich
From: Michael Hennerich <michael.hennerich-OyLXuOCK7orQT0dZR+AlfA@public.gmane.org>
For transfer counts > 255 bytes, the Blackfin TWI peripheral sets the
data transfer counter DCNT to 0xFF indicating unlimited transfers. It
then uses a flag iface->manual_stop to manually issue the STOP condition
once the required amount of bytes are received.
It seems that if the STOP condition is issued with a full receive fifo,
the TWI logic constantly drives the SDA/SCL lines low thus locking the
bus. So to make sure this doesn't happen, consume the fifo first.
Signed-off-by: Michael Hennerich <michael.hennerich-OyLXuOCK7orQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Mike Frysinger <vapier-aBrp7R+bbdUdnm+yROfE0A@public.gmane.org>
---
drivers/i2c/busses/i2c-bfin-twi.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index 52b545a..5ed6c2f 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -131,6 +131,10 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
iface->transPtr++;
iface->readNum--;
} else if (iface->manual_stop) {
+ /* Avoid possible bus stall -
+ * Flush FIFO before issuing the STOP condition
+ */
+ read_RCV_DATA16(iface);
write_MASTER_CTL(iface,
read_MASTER_CTL(iface) | STOP);
} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
--
1.7.5.rc3
^ permalink raw reply related [flat|nested] 4+ messages in thread[parent not found: <1306355198-18530-1-git-send-email-vapier-aBrp7R+bbdUdnm+yROfE0A@public.gmane.org>]
* [PATCH 2/4] i2c-bfin-twi: stop receive operation after last byte rx interrupt [not found] ` <1306355198-18530-1-git-send-email-vapier-aBrp7R+bbdUdnm+yROfE0A@public.gmane.org> @ 2011-05-25 20:26 ` Mike Frysinger 2011-05-25 20:26 ` [PATCH 3/4] i2c-bfin-twi: wake up waiting processes after transfer has finished Mike Frysinger 2011-05-25 20:26 ` [PATCH 4/4] i2c-bfin-twi: add a timeout to busbusy polling Mike Frysinger 2 siblings, 0 replies; 4+ messages in thread From: Mike Frysinger @ 2011-05-25 20:26 UTC (permalink / raw) To: linux-i2c-u79uwXL29TY76Z2rM5mHXA, Ben Dooks Cc: uclinux-dist-devel-ZG0+EudsQA8dtHy/vicBwGD2FQJk+8+b, Sonic Zhang From: Sonic Zhang <sonic.zhang-OyLXuOCK7orQT0dZR+AlfA@public.gmane.org> Once the last byte has been received, we can then move on to further processing of the transfer rather than delaying. This improves the response times with long transfers. Signed-off-by: Sonic Zhang <sonic.zhang-OyLXuOCK7orQT0dZR+AlfA@public.gmane.org> Signed-off-by: Mike Frysinger <vapier-aBrp7R+bbdUdnm+yROfE0A@public.gmane.org> --- drivers/i2c/busses/i2c-bfin-twi.c | 41 ++++++++++++++++++++---------------- 1 files changed, 23 insertions(+), 18 deletions(-) diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 5ed6c2f..aaabd5d 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -130,21 +130,25 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, } iface->transPtr++; iface->readNum--; - } else if (iface->manual_stop) { - /* Avoid possible bus stall - - * Flush FIFO before issuing the STOP condition - */ - read_RCV_DATA16(iface); - write_MASTER_CTL(iface, - read_MASTER_CTL(iface) | STOP); - } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && - iface->cur_msg + 1 < iface->msg_num) { - if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD) - write_MASTER_CTL(iface, - read_MASTER_CTL(iface) | RSTART | MDIR); - else + } + + if (iface->readNum == 0) { + if (iface->manual_stop) { + /* Avoid possible bus stall - + * Flush FIFO before issuing the STOP condition + */ + read_RCV_DATA16(iface); write_MASTER_CTL(iface, - (read_MASTER_CTL(iface) | RSTART) & ~MDIR); + read_MASTER_CTL(iface) | STOP); + } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && + iface->cur_msg + 1 < iface->msg_num) { + if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD) + write_MASTER_CTL(iface, + read_MASTER_CTL(iface) | RSTART | MDIR); + else + write_MASTER_CTL(iface, + (read_MASTER_CTL(iface) | RSTART) & ~MDIR); + } } } if (twi_int_status & MERR) { @@ -239,12 +243,13 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, } } - if (iface->pmsg[iface->cur_msg].len <= 255) - write_MASTER_CTL(iface, + if (iface->pmsg[iface->cur_msg].len <= 255) { + write_MASTER_CTL(iface, (read_MASTER_CTL(iface) & (~(0xff << 6))) | - (iface->pmsg[iface->cur_msg].len << 6)); - else { + (iface->pmsg[iface->cur_msg].len << 6)); + iface->manual_stop = 0; + } else { write_MASTER_CTL(iface, (read_MASTER_CTL(iface) | (0xff << 6))); -- 1.7.5.rc3 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 3/4] i2c-bfin-twi: wake up waiting processes after transfer has finished [not found] ` <1306355198-18530-1-git-send-email-vapier-aBrp7R+bbdUdnm+yROfE0A@public.gmane.org> 2011-05-25 20:26 ` [PATCH 2/4] i2c-bfin-twi: stop receive operation after last byte rx interrupt Mike Frysinger @ 2011-05-25 20:26 ` Mike Frysinger 2011-05-25 20:26 ` [PATCH 4/4] i2c-bfin-twi: add a timeout to busbusy polling Mike Frysinger 2 siblings, 0 replies; 4+ messages in thread From: Mike Frysinger @ 2011-05-25 20:26 UTC (permalink / raw) To: linux-i2c-u79uwXL29TY76Z2rM5mHXA, Ben Dooks Cc: uclinux-dist-devel-ZG0+EudsQA8dtHy/vicBwGD2FQJk+8+b, Sonic Zhang From: Sonic Zhang <sonic.zhang-OyLXuOCK7orQT0dZR+AlfA@public.gmane.org> Rather than waking up the caller on every byte only to have them go back to sleep to wait for the whole transfer to finish, wake up the caller once at the end of the transfer. Signed-off-by: Sonic Zhang <sonic.zhang-OyLXuOCK7orQT0dZR+AlfA@public.gmane.org> Signed-off-by: Mike Frysinger <vapier-aBrp7R+bbdUdnm+yROfE0A@public.gmane.org> --- drivers/i2c/busses/i2c-bfin-twi.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index aaabd5d..64d4b64 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -263,8 +263,8 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, write_INT_MASK(iface, 0); write_MASTER_CTL(iface, 0); } + complete(&iface->complete); } - complete(&iface->complete); } /* Interrupt handler */ -- 1.7.5.rc3 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 4/4] i2c-bfin-twi: add a timeout to busbusy polling [not found] ` <1306355198-18530-1-git-send-email-vapier-aBrp7R+bbdUdnm+yROfE0A@public.gmane.org> 2011-05-25 20:26 ` [PATCH 2/4] i2c-bfin-twi: stop receive operation after last byte rx interrupt Mike Frysinger 2011-05-25 20:26 ` [PATCH 3/4] i2c-bfin-twi: wake up waiting processes after transfer has finished Mike Frysinger @ 2011-05-25 20:26 ` Mike Frysinger 2 siblings, 0 replies; 4+ messages in thread From: Mike Frysinger @ 2011-05-25 20:26 UTC (permalink / raw) To: linux-i2c-u79uwXL29TY76Z2rM5mHXA, Ben Dooks Cc: uclinux-dist-devel-ZG0+EudsQA8dtHy/vicBwGD2FQJk+8+b, Sonic Zhang From: Sonic Zhang <sonic.zhang-OyLXuOCK7orQT0dZR+AlfA@public.gmane.org> Some faulty i2c slave devices might hold the sda/scl line and cause the i2c bus driver to wait indefinitely in the busbusy loop. Add a timeout to the loop so the bus master can recover without locking up everything. Signed-off-by: Sonic Zhang <sonic.zhang-OyLXuOCK7orQT0dZR+AlfA@public.gmane.org> Signed-off-by: Mike Frysinger <vapier-aBrp7R+bbdUdnm+yROfE0A@public.gmane.org> --- drivers/i2c/busses/i2c-bfin-twi.c | 14 ++++++++++++-- 1 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 64d4b64..f2628a7 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -288,6 +288,8 @@ static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id) return IRQ_HANDLED; } +#define BFIN_TWI_BUSY_TIMEOUT 1000 + /* * One i2c master transfer */ @@ -297,12 +299,16 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap, struct bfin_twi_iface *iface = adap->algo_data; struct i2c_msg *pmsg; int rc = 0; + unsigned int busy_timeout = BFIN_TWI_BUSY_TIMEOUT; if (!(read_CONTROL(iface) & TWI_ENA)) return -ENXIO; - while (read_MASTER_STAT(iface) & BUSBUSY) + while (read_MASTER_STAT(iface) & BUSBUSY) { + if (--busy_timeout == 0) + return -EBUSY; yield(); + } iface->pmsg = msgs; iface->msg_num = num; @@ -397,12 +403,16 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr, { struct bfin_twi_iface *iface = adap->algo_data; int rc = 0; + unsigned int busy_timeout = BFIN_TWI_BUSY_TIMEOUT; if (!(read_CONTROL(iface) & TWI_ENA)) return -ENXIO; - while (read_MASTER_STAT(iface) & BUSBUSY) + while (read_MASTER_STAT(iface) & BUSBUSY) { + if (--busy_timeout == 0) + return -EBUSY; yield(); + } iface->writeNum = 0; iface->readNum = 0; -- 1.7.5.rc3 ^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2011-05-25 20:26 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-05-25 20:26 [PATCH 1/4] i2c-bfin-twi: work around illegal i2c bus lock with long transfers Mike Frysinger
[not found] ` <1306355198-18530-1-git-send-email-vapier-aBrp7R+bbdUdnm+yROfE0A@public.gmane.org>
2011-05-25 20:26 ` [PATCH 2/4] i2c-bfin-twi: stop receive operation after last byte rx interrupt Mike Frysinger
2011-05-25 20:26 ` [PATCH 3/4] i2c-bfin-twi: wake up waiting processes after transfer has finished Mike Frysinger
2011-05-25 20:26 ` [PATCH 4/4] i2c-bfin-twi: add a timeout to busbusy polling Mike Frysinger
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).