diff mbox

[U-Boot] i2c: mxs_i2c: Squash endless loop

Message ID 1383413009-4912-1-git-send-email-marex@denx.de
State Superseded
Headers show

Commit Message

Marek Vasut Nov. 2, 2013, 5:23 p.m. UTC
The endless waiting for a bit to be set can cause a hang, add a timeout
so we prevent such situation. A testcase for such a hang is below. The
testcase assumes a device to be present at address 0x50 and a device to
NOT be present at address 0x42 . Also note that the "sleep 1" induced
delays are imperative for this bug to manifest .

i2c read 0x42 0x0.2 0x10 0x42000000 ; sleep 1 ; \
i2c read 0x50 0x0.2 0x10 0x42000000 ; sleep 1 ; \
i2c read 0x42 0x0.2 0x10 0x42000000

The expected result of the above command is:

Error reading the chip.
Error reading the chip.

While without this patch, we observe a hang in the last read from 0x42
precisely when waiting for this bit to be set.

Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Fabio Estevam <fabio.estevam@freescale.com>
Cc: Heiko Schocher <hs@denx.de>
Cc: Stefano Babic <sbabic@denx.de>
---
 drivers/i2c/mxs_i2c.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

Comments

Stefano Babic Nov. 4, 2013, 9:01 a.m. UTC | #1
Hi Marek,

On 02/11/2013 18:23, Marek Vasut wrote:

> +			if (!timeout) {
> +				debug("MXS I2C: Failed receiving data!\n");
> +				return -EINVAL;
> +			}
> +

This is a real error and not a debug information. IMHO it should be
better to print the error unconditionally with puts/printf, reporting
that the timer elapsed.

Best regards,
Stefano Babic
Marek Vasut Nov. 4, 2013, 11:50 a.m. UTC | #2
Hi Stefano,

> Hi Marek,
> 
> On 02/11/2013 18:23, Marek Vasut wrote:
> > +			if (!timeout) {
> > +				debug("MXS I2C: Failed receiving data!\n");
> > +				return -EINVAL;
> > +			}
> > +
> 
> This is a real error and not a debug information. IMHO it should be
> better to print the error unconditionally with puts/printf, reporting
> that the timer elapsed.

Returning -EINVAL will make the i2c stack trigger an output, so having it 
duplicated here is pointless I believe.

Best regards,
Marek Vasut
Stefano Babic Nov. 4, 2013, 12:03 p.m. UTC | #3
Hi Marek,

On 04/11/2013 12:50, Marek Vasut wrote:
> Hi Stefano,
> 
>> Hi Marek,
>>
>> On 02/11/2013 18:23, Marek Vasut wrote:
>>> +			if (!timeout) {
>>> +				debug("MXS I2C: Failed receiving data!\n");
>>> +				return -EINVAL;
>>> +			}
>>> +
>>
>> This is a real error and not a debug information. IMHO it should be
>> better to print the error unconditionally with puts/printf, reporting
>> that the timer elapsed.
> 
> Returning -EINVAL will make the i2c stack trigger an output, so having it 
> duplicated here is pointless I believe.

Agree on that. But then, should we not return -ETIMEDOUT (-110) ? We
should print the error code in the i2c stack (do_i2c_read) instead of
checking only if the return value is not null, as we do now.

Best regards,
Stefano Babic
Heiko Schocher Nov. 4, 2013, 12:18 p.m. UTC | #4
Hello Stefano, Marek,

Am 04.11.2013 13:03, schrieb Stefano Babic:
> Hi Marek,
>
> On 04/11/2013 12:50, Marek Vasut wrote:
>> Hi Stefano,
>>
>>> Hi Marek,
>>>
>>> On 02/11/2013 18:23, Marek Vasut wrote:
>>>> +			if (!timeout) {
>>>> +				debug("MXS I2C: Failed receiving data!\n");
>>>> +				return -EINVAL;
>>>> +			}
>>>> +
>>>
>>> This is a real error and not a debug information. IMHO it should be
>>> better to print the error unconditionally with puts/printf, reporting
>>> that the timer elapsed.
>>
>> Returning -EINVAL will make the i2c stack trigger an output, so having it
>> duplicated here is pointless I believe.
>
> Agree on that. But then, should we not return -ETIMEDOUT (-110) ? We

Yes, that should be -ETIMEDOUT

> should print the error code in the i2c stack (do_i2c_read) instead of
> checking only if the return value is not null, as we do now.

Yep, printing in do_i2c_read()  the error code would be nice. Patches
are welcome :-)

bye,
Heiko
Marek Vasut Nov. 4, 2013, 1:13 p.m. UTC | #5
Hi Heiko,

> Hello Stefano, Marek,
> 
> Am 04.11.2013 13:03, schrieb Stefano Babic:
> > Hi Marek,
> > 
> > On 04/11/2013 12:50, Marek Vasut wrote:
> >> Hi Stefano,
> >> 
> >>> Hi Marek,
> >>> 
> >>> On 02/11/2013 18:23, Marek Vasut wrote:
> >>>> +			if (!timeout) {
> >>>> +				debug("MXS I2C: Failed receiving data!
\n");
> >>>> +				return -EINVAL;
> >>>> +			}
> >>>> +
> >>> 
> >>> This is a real error and not a debug information. IMHO it should be
> >>> better to print the error unconditionally with puts/printf, reporting
> >>> that the timer elapsed.
> >> 
> >> Returning -EINVAL will make the i2c stack trigger an output, so having
> >> it duplicated here is pointless I believe.
> > 
> > Agree on that. But then, should we not return -ETIMEDOUT (-110) ? We
> 
> Yes, that should be -ETIMEDOUT

Full ACK.

> > should print the error code in the i2c stack (do_i2c_read) instead of
> > checking only if the return value is not null, as we do now.
> 
> Yep, printing in do_i2c_read()  the error code would be nice. Patches
> are welcome :-)

OK, shall I also print out an error message then?

Best regards,
Marek Vasut
Heiko Schocher Nov. 4, 2013, 1:21 p.m. UTC | #6
Hello Marek,

Am 04.11.2013 14:13, schrieb Marek Vasut:
> Hi Heiko,
>
>> Hello Stefano, Marek,
>>
>> Am 04.11.2013 13:03, schrieb Stefano Babic:
>>> Hi Marek,
>>>
>>> On 04/11/2013 12:50, Marek Vasut wrote:
>>>> Hi Stefano,
>>>>
>>>>> Hi Marek,
>>>>>
>>>>> On 02/11/2013 18:23, Marek Vasut wrote:
>>>>>> +			if (!timeout) {
>>>>>> +				debug("MXS I2C: Failed receiving data!
> \n");
>>>>>> +				return -EINVAL;
>>>>>> +			}
>>>>>> +
>>>>>
>>>>> This is a real error and not a debug information. IMHO it should be
>>>>> better to print the error unconditionally with puts/printf, reporting
>>>>> that the timer elapsed.
>>>>
>>>> Returning -EINVAL will make the i2c stack trigger an output, so having
>>>> it duplicated here is pointless I believe.
>>>
>>> Agree on that. But then, should we not return -ETIMEDOUT (-110) ? We
>>
>> Yes, that should be -ETIMEDOUT
>
> Full ACK.
>
>>> should print the error code in the i2c stack (do_i2c_read) instead of
>>> checking only if the return value is not null, as we do now.
>>
>> Yep, printing in do_i2c_read()  the error code would be nice. Patches
>> are welcome :-)
>
> OK, shall I also print out an error message then?

You mean in the mxs i2c driver? I think, this is not needed, as
Stefano suggested.

bye,
Heiko
Marek Vasut Nov. 4, 2013, 1:29 p.m. UTC | #7
Dear Heiko Schocher,

> Hello Marek,
> 
> Am 04.11.2013 14:13, schrieb Marek Vasut:
> > Hi Heiko,
> > 
> >> Hello Stefano, Marek,
> >> 
> >> Am 04.11.2013 13:03, schrieb Stefano Babic:
> >>> Hi Marek,
> >>> 
> >>> On 04/11/2013 12:50, Marek Vasut wrote:
> >>>> Hi Stefano,
> >>>> 
> >>>>> Hi Marek,
> >>>>> 
> >>>>> On 02/11/2013 18:23, Marek Vasut wrote:
> >>>>>> +			if (!timeout) {
> >>>>>> +				debug("MXS I2C: Failed receiving data!
> > 
> > \n");
> > 
> >>>>>> +				return -EINVAL;
> >>>>>> +			}
> >>>>>> +
> >>>>> 
> >>>>> This is a real error and not a debug information. IMHO it should be
> >>>>> better to print the error unconditionally with puts/printf, reporting
> >>>>> that the timer elapsed.
> >>>> 
> >>>> Returning -EINVAL will make the i2c stack trigger an output, so having
> >>>> it duplicated here is pointless I believe.
> >>> 
> >>> Agree on that. But then, should we not return -ETIMEDOUT (-110) ? We
> >> 
> >> Yes, that should be -ETIMEDOUT
> > 
> > Full ACK.
> > 
> >>> should print the error code in the i2c stack (do_i2c_read) instead of
> >>> checking only if the return value is not null, as we do now.
> >> 
> >> Yep, printing in do_i2c_read()  the error code would be nice. Patches
> >> are welcome :-)
> > 
> > OK, shall I also print out an error message then?
> 
> You mean in the mxs i2c driver? I think, this is not needed, as
> Stefano suggested.

OK, thanks! V2 out.

Best regards,
Marek Vasut
diff mbox

Patch

diff --git a/drivers/i2c/mxs_i2c.c b/drivers/i2c/mxs_i2c.c
index 46106b7..49300d4 100644
--- a/drivers/i2c/mxs_i2c.c
+++ b/drivers/i2c/mxs_i2c.c
@@ -150,6 +150,7 @@  int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
 {
 	struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE;
 	uint32_t tmp = 0;
+	int timeout = MXS_I2C_MAX_TIMEOUT;
 	int ret;
 	int i;
 
@@ -169,9 +170,17 @@  int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
 
 	for (i = 0; i < len; i++) {
 		if (!(i & 3)) {
-			while (readl(&i2c_regs->hw_i2c_queuestat) &
-				I2C_QUEUESTAT_RD_QUEUE_EMPTY)
-				;
+			while (--timeout) {
+				tmp = readl(&i2c_regs->hw_i2c_queuestat);
+				if (!(tmp & I2C_QUEUESTAT_RD_QUEUE_EMPTY))
+					break;
+			}
+
+			if (!timeout) {
+				debug("MXS I2C: Failed receiving data!\n");
+				return -EINVAL;
+			}
+
 			tmp = readl(&i2c_regs->hw_i2c_queuedata);
 		}
 		buffer[i] = tmp & 0xff;