2023-11-02 03:31:24

by Tam Nguyen

[permalink] [raw]
Subject: [PATCH v2] i2c: designware: Disable TX_EMPTY irq while waiting for block length byte

During SMBus block data read process, we have seen high interrupt rate
because of TX_EMPTY irq status while waiting for block length byte (the
first data byte after the address phase). The interrupt handler does not
do anything because the internal state is kept as STATUS_WRITE_IN_PROGRESS.
Hence, we should disable TX_EMPTY IRQ until I2C DesignWare receives
first data byte from I2C device, then re-enable it to resume SMBus
transaction.

It takes 0.789 ms for host to receive data length from slave.
Without the patch, i2c_dw_isr() is called 99 times by TX_EMPTY interrupt.
And it is none after applying the patch.

Cc: [email protected]
Co-developed-by: Chuong Tran <[email protected]>
Signed-off-by: Chuong Tran <[email protected]>
Signed-off-by: Tam Nguyen <[email protected]>
---
v2:
+ Reduce the indentations level
+ Use regmap_update_bits for bitfield update
+ Rewrite comment statement [Serge]
+ Update commit message
+ Add Co-developed-by tag for co-authors [Andy]

v1:
https://lore.kernel.org/lkml/avd7jhwexehgbvi6euzdwvf5zvqqgjx4ozo6uxu2qpmlarvva3@sgkce3rvovwk/T/
---
drivers/i2c/busses/i2c-designware-master.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index 55ea91a63382..ae76620ef35e 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -456,10 +456,16 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)

/*
* Because we don't know the buffer length in the
- * I2C_FUNC_SMBUS_BLOCK_DATA case, we can't stop
- * the transaction here.
+ * I2C_FUNC_SMBUS_BLOCK_DATA case, we can't stop the
+ * transaction here. Also disable the TX_EMPTY IRQ
+ * while waiting for the data length byte to avoid the
+ * bogus interrupts flood.
*/
- if (buf_len > 0 || flags & I2C_M_RECV_LEN) {
+ if (flags & I2C_M_RECV_LEN) {
+ dev->status |= STATUS_WRITE_IN_PROGRESS;
+ intr_mask &= ~DW_IC_INTR_TX_EMPTY;
+ break;
+ } else if (buf_len > 0) {
/* more bytes to be written */
dev->status |= STATUS_WRITE_IN_PROGRESS;
break;
@@ -495,6 +501,13 @@ i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len)
msgs[dev->msg_read_idx].len = len;
msgs[dev->msg_read_idx].flags &= ~I2C_M_RECV_LEN;

+ /*
+ * Received buffer length, re-enable TX_EMPTY interrupt
+ * to resume the SMBUS transaction.
+ */
+ regmap_update_bits(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_TX_EMPTY,
+ DW_IC_INTR_TX_EMPTY);
+
return len;
}

--
2.25.1


2023-11-03 12:59:51

by Jarkko Nikula

[permalink] [raw]
Subject: Re: [PATCH v2] i2c: designware: Disable TX_EMPTY irq while waiting for block length byte

On 11/2/23 05:30, Tam Nguyen wrote:
> During SMBus block data read process, we have seen high interrupt rate
> because of TX_EMPTY irq status while waiting for block length byte (the
> first data byte after the address phase). The interrupt handler does not
> do anything because the internal state is kept as STATUS_WRITE_IN_PROGRESS.
> Hence, we should disable TX_EMPTY IRQ until I2C DesignWare receives
> first data byte from I2C device, then re-enable it to resume SMBus
> transaction.
>
> It takes 0.789 ms for host to receive data length from slave.
> Without the patch, i2c_dw_isr() is called 99 times by TX_EMPTY interrupt.
> And it is none after applying the patch.
>
> Cc: [email protected]
> Co-developed-by: Chuong Tran <[email protected]>
> Signed-off-by: Chuong Tran <[email protected]>
> Signed-off-by: Tam Nguyen <[email protected]>
> ---
> v2:
> + Reduce the indentations level
> + Use regmap_update_bits for bitfield update
> + Rewrite comment statement [Serge]
> + Update commit message
> + Add Co-developed-by tag for co-authors [Andy]
>
> v1:
> https://lore.kernel.org/lkml/avd7jhwexehgbvi6euzdwvf5zvqqgjx4ozo6uxu2qpmlarvva3@sgkce3rvovwk/T/
> ---
> drivers/i2c/busses/i2c-designware-master.c | 19 ++++++++++++++++---
> 1 file changed, 16 insertions(+), 3 deletions(-)
>
Acked-by: Jarkko Nikula <[email protected]>

2023-11-03 13:02:41

by Serge Semin

[permalink] [raw]
Subject: Re: [PATCH v2] i2c: designware: Disable TX_EMPTY irq while waiting for block length byte

On Thu, Nov 02, 2023 at 10:30:08AM +0700, Tam Nguyen wrote:
> During SMBus block data read process, we have seen high interrupt rate
> because of TX_EMPTY irq status while waiting for block length byte (the
> first data byte after the address phase). The interrupt handler does not
> do anything because the internal state is kept as STATUS_WRITE_IN_PROGRESS.
> Hence, we should disable TX_EMPTY IRQ until I2C DesignWare receives
> first data byte from I2C device, then re-enable it to resume SMBus
> transaction.
>
> It takes 0.789 ms for host to receive data length from slave.
> Without the patch, i2c_dw_isr() is called 99 times by TX_EMPTY interrupt.
> And it is none after applying the patch.
>
> Cc: [email protected]
> Co-developed-by: Chuong Tran <[email protected]>
> Signed-off-by: Chuong Tran <[email protected]>
> Signed-off-by: Tam Nguyen <[email protected]>

Thanks!
Reviewed-by: Serge Semin <[email protected]>

-Serge(y)

> ---
> v2:
> + Reduce the indentations level
> + Use regmap_update_bits for bitfield update
> + Rewrite comment statement [Serge]
> + Update commit message
> + Add Co-developed-by tag for co-authors [Andy]
>
> v1:
> https://lore.kernel.org/lkml/avd7jhwexehgbvi6euzdwvf5zvqqgjx4ozo6uxu2qpmlarvva3@sgkce3rvovwk/T/
> ---
> drivers/i2c/busses/i2c-designware-master.c | 19 ++++++++++++++++---
> 1 file changed, 16 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
> index 55ea91a63382..ae76620ef35e 100644
> --- a/drivers/i2c/busses/i2c-designware-master.c
> +++ b/drivers/i2c/busses/i2c-designware-master.c
> @@ -456,10 +456,16 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
>
> /*
> * Because we don't know the buffer length in the
> - * I2C_FUNC_SMBUS_BLOCK_DATA case, we can't stop
> - * the transaction here.
> + * I2C_FUNC_SMBUS_BLOCK_DATA case, we can't stop the
> + * transaction here. Also disable the TX_EMPTY IRQ
> + * while waiting for the data length byte to avoid the
> + * bogus interrupts flood.
> */
> - if (buf_len > 0 || flags & I2C_M_RECV_LEN) {
> + if (flags & I2C_M_RECV_LEN) {
> + dev->status |= STATUS_WRITE_IN_PROGRESS;
> + intr_mask &= ~DW_IC_INTR_TX_EMPTY;
> + break;
> + } else if (buf_len > 0) {
> /* more bytes to be written */
> dev->status |= STATUS_WRITE_IN_PROGRESS;
> break;
> @@ -495,6 +501,13 @@ i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len)
> msgs[dev->msg_read_idx].len = len;
> msgs[dev->msg_read_idx].flags &= ~I2C_M_RECV_LEN;
>
> + /*
> + * Received buffer length, re-enable TX_EMPTY interrupt
> + * to resume the SMBUS transaction.
> + */
> + regmap_update_bits(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_TX_EMPTY,
> + DW_IC_INTR_TX_EMPTY);
> +
> return len;
> }
>
> --
> 2.25.1
>