* i2c-i801 retries on lost arbitration (resent: no gpg)
@ 2010-04-30 9:44 Sergey Senozhatsky
2010-04-30 9:48 ` Jean Delvare
0 siblings, 1 reply; 3+ messages in thread
From: Sergey Senozhatsky @ 2010-04-30 9:44 UTC (permalink / raw)
To: Jean Delvare (PC drivers, core)
Cc: Ben Dooks (embedded platforms), Wolfram Sang,
linux-i2c-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Soory, forgot to turn-off gpg.
Both i2c spec and ICH7 datasheet requires to restart transaction in
case of lost arbitration.
"No information is lost during the arbitration process. A master that
loses the arbitration can generate clock pulses until the end of the
byte in which it loses the arbitration and must restart its transaction
when the bus is idle."
Please see the following patch. Is it correct?
---
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 299b918..b7c21ee 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -446,100 +446,111 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr,
{
int hwpec;
int block = 0;
- int ret, xact = 0;
-
+ int ret, xact = 0, i = 0;
+
hwpec = (i801_features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
&& size != I2C_SMBUS_QUICK
&& size != I2C_SMBUS_I2C_BLOCK_DATA;
- switch (size) {
- case I2C_SMBUS_QUICK:
- outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
- SMBHSTADD);
- xact = I801_QUICK;
- break;
- case I2C_SMBUS_BYTE:
- outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
- SMBHSTADD);
- if (read_write == I2C_SMBUS_WRITE)
+ for (i = adap->retries; i >= 0; i--) {
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ xact = I801_QUICK;
+ break;
+ case I2C_SMBUS_BYTE:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(command, SMBHSTCMD);
+ xact = I801_BYTE;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
outb_p(command, SMBHSTCMD);
- xact = I801_BYTE;
- break;
- case I2C_SMBUS_BYTE_DATA:
- outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
- SMBHSTADD);
- outb_p(command, SMBHSTCMD);
- if (read_write == I2C_SMBUS_WRITE)
- outb_p(data->byte, SMBHSTDAT0);
- xact = I801_BYTE_DATA;
- break;
- case I2C_SMBUS_WORD_DATA:
- outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
- SMBHSTADD);
- outb_p(command, SMBHSTCMD);
- if (read_write == I2C_SMBUS_WRITE) {
- outb_p(data->word & 0xff, SMBHSTDAT0);
- outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
- }
- xact = I801_WORD_DATA;
- break;
- case I2C_SMBUS_BLOCK_DATA:
- outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
- SMBHSTADD);
- outb_p(command, SMBHSTCMD);
- block = 1;
- break;
- case I2C_SMBUS_I2C_BLOCK_DATA:
- /* NB: page 240 of ICH5 datasheet shows that the R/#W
- * bit should be cleared here, even when reading */
- outb_p((addr & 0x7f) << 1, SMBHSTADD);
- if (read_write == I2C_SMBUS_READ) {
- /* NB: page 240 of ICH5 datasheet also shows
- * that DATA1 is the cmd field when reading */
- outb_p(command, SMBHSTDAT1);
- } else
+ if (read_write == I2C_SMBUS_WRITE)
+ outb_p(data->byte, SMBHSTDAT0);
+ xact = I801_BYTE_DATA;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
outb_p(command, SMBHSTCMD);
- block = 1;
- break;
- default:
- dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size);
- return -EOPNOTSUPP;
- }
-
- if (hwpec) /* enable/disable hardware PEC */
- outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_CRC, SMBAUXCTL);
- else
- outb_p(inb_p(SMBAUXCTL) & (~SMBAUXCTL_CRC), SMBAUXCTL);
-
- if(block)
- ret = i801_block_transaction(data, read_write, size, hwpec);
- else
- ret = i801_transaction(xact | ENABLE_INT9);
-
- /* Some BIOSes don't like it when PEC is enabled at reboot or resume
- time, so we forcibly disable it after every transaction. Turn off
- E32B for the same reason. */
- if (hwpec || block)
- outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
- SMBAUXCTL);
+ if (read_write == I2C_SMBUS_WRITE) {
+ outb_p(data->word & 0xff, SMBHSTDAT0);
+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+ }
+ xact = I801_WORD_DATA;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+ SMBHSTADD);
+ outb_p(command, SMBHSTCMD);
+ block = 1;
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ /* NB: page 240 of ICH5 datasheet shows that the R/#W
+ * bit should be cleared here, even when reading */
+ outb_p((addr & 0x7f) << 1, SMBHSTADD);
+ if (read_write == I2C_SMBUS_READ) {
+ /* NB: page 240 of ICH5 datasheet also shows
+ * that DATA1 is the cmd field when reading */
+ outb_p(command, SMBHSTDAT1);
+ } else
+ outb_p(command, SMBHSTCMD);
+ block = 1;
+ break;
+ default:
+ dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size);
+ return -EOPNOTSUPP;
+ }
+
+ if (hwpec) /* enable/disable hardware PEC */
+ outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_CRC, SMBAUXCTL);
+ else
+ outb_p(inb_p(SMBAUXCTL) & (~SMBAUXCTL_CRC), SMBAUXCTL);
+
+ if(block)
+ ret = i801_block_transaction(data, read_write, size, hwpec);
+ else
+ ret = i801_transaction(xact | ENABLE_INT9);
+
+ /* Some BIOSes don't like it when PEC is enabled at reboot or resume
+ time, so we forcibly disable it after every transaction. Turn off
+ E32B for the same reason. */
+ if (hwpec || block)
+ outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
+ SMBAUXCTL);
+
+ if (ret == -EAGAIN) {
+ dev_dbg(&I801_dev->dev, "Restarting transaction (probably due to lost arbitration)");
+ continue;
+ }
+
+ if(block)
+ return ret;
+ if(ret)
+ return ret;
+ if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))
+ return 0;
+
+ switch (xact & 0x7f) {
+ case I801_BYTE: /* Result put in SMBHSTDAT0 */
+ case I801_BYTE_DATA:
+ data->byte = inb_p(SMBHSTDAT0);
+ break;
+ case I801_WORD_DATA:
+ data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
+ break;
+ }
- if(block)
- return ret;
- if(ret)
- return ret;
- if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))
return 0;
-
- switch (xact & 0x7f) {
- case I801_BYTE: /* Result put in SMBHSTDAT0 */
- case I801_BYTE_DATA:
- data->byte = inb_p(SMBHSTDAT0);
- break;
- case I801_WORD_DATA:
- data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
- break;
}
- return 0;
+
+ ret = -EREMOTEIO;
+ return ret;
}
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: i2c-i801 retries on lost arbitration (resent: no gpg)
2010-04-30 9:44 i2c-i801 retries on lost arbitration (resent: no gpg) Sergey Senozhatsky
@ 2010-04-30 9:48 ` Jean Delvare
2010-04-30 10:07 ` Sergey Senozhatsky
0 siblings, 1 reply; 3+ messages in thread
From: Jean Delvare @ 2010-04-30 9:48 UTC (permalink / raw)
To: Sergey Senozhatsky
Cc: Ben Dooks (embedded platforms), Wolfram Sang, linux-i2c,
linux-kernel
Hi Sergey,
On Fri, 30 Apr 2010 12:44:12 +0300, Sergey Senozhatsky wrote:
> Soory, forgot to turn-off gpg.
gpg is fine.
> Both i2c spec and ICH7 datasheet requires to restart transaction in
> case of lost arbitration.
>
> "No information is lost during the arbitration process. A master that
> loses the arbitration can generate clock pulses until the end of the
> byte in which it loses the arbitration and must restart its transaction
> when the bus is idle."
>
> Please see the following patch. Is it correct?
No, it's not. As you wrote above, this is not specific to the Intel ICH
but a general I2C issue. As such it must be handled in i2c-core and not
by individual drivers. And as a matter of fact, it is already handled.
Look at functions i2c_transfer and i2c_smbus_xfer in i2c-core.c, see
the comments "Retry automatically on arbitration loss", the code is
already there. It's just a matter of bus drivers properly setting
adapter->retries (which i2c-i801.c does already.)
So I don't know which kernel you're using, but with the latest upstream
kernel, things should work just fine already.
--
Jean Delvare
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: i2c-i801 retries on lost arbitration (resent: no gpg)
2010-04-30 9:48 ` Jean Delvare
@ 2010-04-30 10:07 ` Sergey Senozhatsky
0 siblings, 0 replies; 3+ messages in thread
From: Sergey Senozhatsky @ 2010-04-30 10:07 UTC (permalink / raw)
To: Jean Delvare
Cc: Ben Dooks (embedded platforms), Wolfram Sang, linux-i2c,
linux-kernel
[-- Attachment #1: Type: text/plain, Size: 1169 bytes --]
On (04/30/10 11:48), Jean Delvare wrote:
> Hi Sergey,
>
>
> > Both i2c spec and ICH7 datasheet requires to restart transaction in
> > case of lost arbitration.
> >
> > "No information is lost during the arbitration process. A master that
> > loses the arbitration can generate clock pulses until the end of the
> > byte in which it loses the arbitration and must restart its transaction
> > when the bus is idle."
> >
> > Please see the following patch. Is it correct?
>
> No, it's not. As you wrote above, this is not specific to the Intel ICH
> but a general I2C issue. As such it must be handled in i2c-core and not
> by individual drivers. And as a matter of fact, it is already handled.
> Look at functions i2c_transfer and i2c_smbus_xfer in i2c-core.c, see
> the comments "Retry automatically on arbitration loss", the code is
> already there. It's just a matter of bus drivers properly setting
> adapter->retries (which i2c-i801.c does already.)
>
Thanks.
> So I don't know which kernel you're using, but with the latest upstream
> kernel, things should work just fine already.
>
OK. Thanks a lot.
Sergey
[-- Attachment #2: Type: application/pgp-signature, Size: 316 bytes --]
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2010-04-30 10:07 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-04-30 9:44 i2c-i801 retries on lost arbitration (resent: no gpg) Sergey Senozhatsky
2010-04-30 9:48 ` Jean Delvare
2010-04-30 10:07 ` Sergey Senozhatsky
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).