linux-i2c.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1] i2c: designware: Handle invalid SMBus block data response length
@ 2023-05-23  8:21 Tam Nguyen
  2023-05-24 12:33 ` Jarkko Nikula
  0 siblings, 1 reply; 5+ messages in thread
From: Tam Nguyen @ 2023-05-23  8:21 UTC (permalink / raw)
  To: linux-kernel, linux-i2c
  Cc: patches, jarkko.nikula, andriy.shevchenko, mika.westerberg, jsd,
	tamnguyenchi, chuong, darren, stable

In I2C_FUNC_SMBUS_BLOCK_DATA case, the I2C Designware driver does not
handle correctly when it receives the length of SMBus block data
response from SMBus slave device, which is outside the range 1-32 bytes.
Consequently, the I2C Designware bus is stuck and cannot recover.
Because if IC_EMPTYFIFO_HOLD_MASTER_EN is set, which cannot be detected
from the registers, the controller can be disabled if the STOP bit is set.
But it is only set after receiving block data response length.

Hence, to prevent the bus from stuck condition, after receiving the
invalid block data response length, the driver will read another byte
with STOP bit set.

Cc: stable@vger.kernel.org
Signed-off-by: Tam Nguyen <tamnguyenchi@os.amperecomputing.com>
---
 drivers/i2c/busses/i2c-designware-master.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index 55ea91a63382..94dadd785ed0 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -527,8 +527,19 @@ i2c_dw_read(struct dw_i2c_dev *dev)
 
 			regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
 			/* Ensure length byte is a valid value */
-			if (flags & I2C_M_RECV_LEN &&
-			    (tmp & DW_IC_DATA_CMD_DAT) <= I2C_SMBUS_BLOCK_MAX && tmp > 0) {
+			if (flags & I2C_M_RECV_LEN) {
+				/*
+				 * if IC_EMPTYFIFO_HOLD_MASTER_EN is set, which cannot be
+				 * detected from the registers, the controller can be
+				 * disabled if the STOP bit is set. But it is only set
+				 * after receiving block data response length in
+				 * I2C_FUNC_SMBUS_BLOCK_DATA case. That needs to read
+				 * another byte with STOP bit set when the block data
+				 * response length is invalid to complete the transaction.
+				 */
+				if ((tmp & DW_IC_DATA_CMD_DAT) > I2C_SMBUS_BLOCK_MAX || tmp == 0)
+					tmp = 1;
+
 				len = i2c_dw_recv_len(dev, tmp);
 			}
 			*buf++ = tmp;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v1] i2c: designware: Handle invalid SMBus block data response length
  2023-05-23  8:21 [PATCH v1] i2c: designware: Handle invalid SMBus block data response length Tam Nguyen
@ 2023-05-24 12:33 ` Jarkko Nikula
  2023-05-25  9:30   ` Tam Chi Nguyen
  0 siblings, 1 reply; 5+ messages in thread
From: Jarkko Nikula @ 2023-05-24 12:33 UTC (permalink / raw)
  To: Tam Nguyen, linux-kernel, linux-i2c
  Cc: patches, andriy.shevchenko, mika.westerberg, jsd, chuong, darren, stable

Hi

On 5/23/23 11:21, Tam Nguyen wrote:
> In I2C_FUNC_SMBUS_BLOCK_DATA case, the I2C Designware driver does not
> handle correctly when it receives the length of SMBus block data
> response from SMBus slave device, which is outside the range 1-32 bytes.
> Consequently, the I2C Designware bus is stuck and cannot recover.
> Because if IC_EMPTYFIFO_HOLD_MASTER_EN is set, which cannot be detected
> from the registers, the controller can be disabled if the STOP bit is set.
> But it is only set after receiving block data response length.
> 
> Hence, to prevent the bus from stuck condition, after receiving the
> invalid block data response length, the driver will read another byte
> with STOP bit set.
> 
> Cc: stable@vger.kernel.org
> Signed-off-by: Tam Nguyen <tamnguyenchi@os.amperecomputing.com>
> ---
>   drivers/i2c/busses/i2c-designware-master.c | 15 +++++++++++++--
>   1 file changed, 13 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
> index 55ea91a63382..94dadd785ed0 100644
> --- a/drivers/i2c/busses/i2c-designware-master.c
> +++ b/drivers/i2c/busses/i2c-designware-master.c
> @@ -527,8 +527,19 @@ i2c_dw_read(struct dw_i2c_dev *dev)
>   
>   			regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
>   			/* Ensure length byte is a valid value */
> -			if (flags & I2C_M_RECV_LEN &&
> -			    (tmp & DW_IC_DATA_CMD_DAT) <= I2C_SMBUS_BLOCK_MAX && tmp > 0) {
> +			if (flags & I2C_M_RECV_LEN) {
> +				/*
> +				 * if IC_EMPTYFIFO_HOLD_MASTER_EN is set, which cannot be
> +				 * detected from the registers, the controller can be
> +				 * disabled if the STOP bit is set. But it is only set
> +				 * after receiving block data response length in
> +				 * I2C_FUNC_SMBUS_BLOCK_DATA case. That needs to read
> +				 * another byte with STOP bit set when the block data
> +				 * response length is invalid to complete the transaction.
> +				 */
> +				if ((tmp & DW_IC_DATA_CMD_DAT) > I2C_SMBUS_BLOCK_MAX || tmp == 0)
> +					tmp = 1;
> +
>   				len = i2c_dw_recv_len(dev, tmp);
>   			}
>   			*buf++ = tmp;

Looks otherwise good to me but I'm wondering the "tmp == 0" test can it 
have the bit 11 set (on a HW where it's supported) and should it be 
covered with DW_IC_DATA_CMD_DAT mask too? Please see commit f53f15ba5a85 
("i2c: designware: Get right data length").

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v1] i2c: designware: Handle invalid SMBus block data response length
  2023-05-24 12:33 ` Jarkko Nikula
@ 2023-05-25  9:30   ` Tam Chi Nguyen
  2023-06-02  4:30     ` Tam Chi Nguyen
  0 siblings, 1 reply; 5+ messages in thread
From: Tam Chi Nguyen @ 2023-05-25  9:30 UTC (permalink / raw)
  To: Jarkko Nikula, Tam Nguyen, linux-kernel, linux-i2c
  Cc: patches, andriy.shevchenko, mika.westerberg, jsd, chuong, darren, stable

Hi Jarkko

On 5/24/2023 19:33, Jarkko Nikula wrote:
> Hi
>
> On 5/23/23 11:21, Tam Nguyen wrote:
>> In I2C_FUNC_SMBUS_BLOCK_DATA case, the I2C Designware driver does not
>> handle correctly when it receives the length of SMBus block data
>> response from SMBus slave device, which is outside the range 1-32 bytes.
>> Consequently, the I2C Designware bus is stuck and cannot recover.
>> Because if IC_EMPTYFIFO_HOLD_MASTER_EN is set, which cannot be detected
>> from the registers, the controller can be disabled if the STOP bit is 
>> set.
>> But it is only set after receiving block data response length.
>>
>> Hence, to prevent the bus from stuck condition, after receiving the
>> invalid block data response length, the driver will read another byte
>> with STOP bit set.
>>
>> Cc: stable@vger.kernel.org
>> Signed-off-by: Tam Nguyen <tamnguyenchi@os.amperecomputing.com>
>> ---
>>   drivers/i2c/busses/i2c-designware-master.c | 15 +++++++++++++--
>>   1 file changed, 13 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/i2c/busses/i2c-designware-master.c 
>> b/drivers/i2c/busses/i2c-designware-master.c
>> index 55ea91a63382..94dadd785ed0 100644
>> --- a/drivers/i2c/busses/i2c-designware-master.c
>> +++ b/drivers/i2c/busses/i2c-designware-master.c
>> @@ -527,8 +527,19 @@ i2c_dw_read(struct dw_i2c_dev *dev)
>>                 regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
>>               /* Ensure length byte is a valid value */
>> -            if (flags & I2C_M_RECV_LEN &&
>> -                (tmp & DW_IC_DATA_CMD_DAT) <= I2C_SMBUS_BLOCK_MAX && 
>> tmp > 0) {
>> +            if (flags & I2C_M_RECV_LEN) {
>> +                /*
>> +                 * if IC_EMPTYFIFO_HOLD_MASTER_EN is set, which 
>> cannot be
>> +                 * detected from the registers, the controller can be
>> +                 * disabled if the STOP bit is set. But it is only set
>> +                 * after receiving block data response length in
>> +                 * I2C_FUNC_SMBUS_BLOCK_DATA case. That needs to read
>> +                 * another byte with STOP bit set when the block data
>> +                 * response length is invalid to complete the 
>> transaction.
>> +                 */
>> +                if ((tmp & DW_IC_DATA_CMD_DAT) > I2C_SMBUS_BLOCK_MAX 
>> || tmp == 0)
>> +                    tmp = 1;
>> +
>>                   len = i2c_dw_recv_len(dev, tmp);
>>               }
>>               *buf++ = tmp;
>
> Looks otherwise good to me but I'm wondering the "tmp == 0" test can 
> it have the bit 11 set (on a HW where it's supported) and should it be 
> covered with DW_IC_DATA_CMD_DAT mask too? Please see commit 
> f53f15ba5a85 ("i2c: designware: Get right data length").

You're right. We should use the DW_IC_DATA_CMD_DAT mask to get the data 
part if HW supports reading bit 11 from IC_DATA_CMD. I will update it in v2.

Best regards,
Tam Nguyen


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v1] i2c: designware: Handle invalid SMBus block data response length
  2023-05-25  9:30   ` Tam Chi Nguyen
@ 2023-06-02  4:30     ` Tam Chi Nguyen
  2023-06-05  7:41       ` Jarkko Nikula
  0 siblings, 1 reply; 5+ messages in thread
From: Tam Chi Nguyen @ 2023-06-02  4:30 UTC (permalink / raw)
  To: Jarkko Nikula, Tam Nguyen, linux-kernel, linux-i2c
  Cc: patches, andriy.shevchenko, mika.westerberg, jsd, chuong, darren, stable

Hi Jarkko,

Before pushing the v2 patch, I have one more question to ask.

The commit f53f15ba5a85 ("i2c: designware: Get right data length"), you 
mentioned,
does not handle bit 11 set (on a HW where it's supported) correctly.
"tmp" was not marked with DW_IC_DATA_CMD_DAT when passing to 
i2c_dw_recv_len function.

So I plan to update it in the v2 patch by adding this
     regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
     tmp &= DW_IC_DATA_CMD_DAT;

My question is: does it need a separate patch for this change?

Best regards,
Tam Nguyen


On 5/25/2023 16:30, Tam Chi Nguyen wrote:
> Hi Jarkko
>
> On 5/24/2023 19:33, Jarkko Nikula wrote:
>> Hi
>>
>> On 5/23/23 11:21, Tam Nguyen wrote:
>>> In I2C_FUNC_SMBUS_BLOCK_DATA case, the I2C Designware driver does not
>>> handle correctly when it receives the length of SMBus block data
>>> response from SMBus slave device, which is outside the range 1-32 
>>> bytes.
>>> Consequently, the I2C Designware bus is stuck and cannot recover.
>>> Because if IC_EMPTYFIFO_HOLD_MASTER_EN is set, which cannot be detected
>>> from the registers, the controller can be disabled if the STOP bit 
>>> is set.
>>> But it is only set after receiving block data response length.
>>>
>>> Hence, to prevent the bus from stuck condition, after receiving the
>>> invalid block data response length, the driver will read another byte
>>> with STOP bit set.
>>>
>>> Cc: stable@vger.kernel.org
>>> Signed-off-by: Tam Nguyen <tamnguyenchi@os.amperecomputing.com>
>>> ---
>>>   drivers/i2c/busses/i2c-designware-master.c | 15 +++++++++++++--
>>>   1 file changed, 13 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/i2c/busses/i2c-designware-master.c 
>>> b/drivers/i2c/busses/i2c-designware-master.c
>>> index 55ea91a63382..94dadd785ed0 100644
>>> --- a/drivers/i2c/busses/i2c-designware-master.c
>>> +++ b/drivers/i2c/busses/i2c-designware-master.c
>>> @@ -527,8 +527,19 @@ i2c_dw_read(struct dw_i2c_dev *dev)
>>>                 regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
>>>               /* Ensure length byte is a valid value */
>>> -            if (flags & I2C_M_RECV_LEN &&
>>> -                (tmp & DW_IC_DATA_CMD_DAT) <= I2C_SMBUS_BLOCK_MAX 
>>> && tmp > 0) {
>>> +            if (flags & I2C_M_RECV_LEN) {
>>> +                /*
>>> +                 * if IC_EMPTYFIFO_HOLD_MASTER_EN is set, which 
>>> cannot be
>>> +                 * detected from the registers, the controller can be
>>> +                 * disabled if the STOP bit is set. But it is only set
>>> +                 * after receiving block data response length in
>>> +                 * I2C_FUNC_SMBUS_BLOCK_DATA case. That needs to read
>>> +                 * another byte with STOP bit set when the block data
>>> +                 * response length is invalid to complete the 
>>> transaction.
>>> +                 */
>>> +                if ((tmp & DW_IC_DATA_CMD_DAT) > 
>>> I2C_SMBUS_BLOCK_MAX || tmp == 0)
>>> +                    tmp = 1;
>>> +
>>>                   len = i2c_dw_recv_len(dev, tmp);
>>>               }
>>>               *buf++ = tmp;
>>
>> Looks otherwise good to me but I'm wondering the "tmp == 0" test can 
>> it have the bit 11 set (on a HW where it's supported) and should it 
>> be covered with DW_IC_DATA_CMD_DAT mask too? Please see commit 
>> f53f15ba5a85 ("i2c: designware: Get right data length").
>
> You're right. We should use the DW_IC_DATA_CMD_DAT mask to get the 
> data part if HW supports reading bit 11 from IC_DATA_CMD. I will 
> update it in v2.
>
> Best regards,
> Tam Nguyen
>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v1] i2c: designware: Handle invalid SMBus block data response length
  2023-06-02  4:30     ` Tam Chi Nguyen
@ 2023-06-05  7:41       ` Jarkko Nikula
  0 siblings, 0 replies; 5+ messages in thread
From: Jarkko Nikula @ 2023-06-05  7:41 UTC (permalink / raw)
  To: Tam Chi Nguyen, Tam Nguyen, linux-kernel, linux-i2c
  Cc: patches, andriy.shevchenko, mika.westerberg, jsd, chuong, darren, stable

Hi

On 6/2/23 07:30, Tam Chi Nguyen wrote:
> Hi Jarkko,
> 
> Before pushing the v2 patch, I have one more question to ask.
> 
> The commit f53f15ba5a85 ("i2c: designware: Get right data length"), you 
> mentioned,
> does not handle bit 11 set (on a HW where it's supported) correctly.
> "tmp" was not marked with DW_IC_DATA_CMD_DAT when passing to 
> i2c_dw_recv_len function.
> 
> So I plan to update it in the v2 patch by adding this
>      regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
>      tmp &= DW_IC_DATA_CMD_DAT;
> 
> My question is: does it need a separate patch for this change?
> 
I think for now bit 11 gets masked since tmp variable is assigned to u8 
variables when calling i2c_dw_recv_len() and writing to *buf pointer but 
your proposal indeed makes code more robust both your patch point of 
view or any other future change. So separate patch makes sense in my 
opinion.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2023-06-05  7:41 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-23  8:21 [PATCH v1] i2c: designware: Handle invalid SMBus block data response length Tam Nguyen
2023-05-24 12:33 ` Jarkko Nikula
2023-05-25  9:30   ` Tam Chi Nguyen
2023-06-02  4:30     ` Tam Chi Nguyen
2023-06-05  7:41       ` Jarkko Nikula

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).