lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20230929035356.6435-1-tamnguyenchi@os.amperecomputing.com>
Date:   Fri, 29 Sep 2023 10:53:56 +0700
From:   Tam Nguyen <tamnguyenchi@...amperecomputing.com>
To:     linux-kernel@...r.kernel.org, linux-i2c@...r.kernel.org
Cc:     patches@...erecomputing.com, jarkko.nikula@...ux.intel.com,
        andriy.shevchenko@...ux.intel.com, mika.westerberg@...ux.intel.com,
        jsd@...ihalf.com, tamnguyenchi@...amperecomputing.com,
        chuong@...amperecomputing.com, darren@...amperecomputing.com,
        stable@...r.kernel.org
Subject: [PATCH v1] 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 DW receives first data
byte from I2C device, then re-enable it.

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: stable@...r.kernel.org
Signed-off-by: Chuong Tran <chuong@...amperecomputing.com>
Signed-off-by: Tam Nguyen <tamnguyenchi@...amperecomputing.com>
---
 drivers/i2c/busses/i2c-designware-master.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c
index 55ea91a63382..2152b1f9b27c 100644
--- a/drivers/i2c/busses/i2c-designware-master.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -462,6 +462,13 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
 		if (buf_len > 0 || flags & I2C_M_RECV_LEN) {
 			/* more bytes to be written */
 			dev->status |= STATUS_WRITE_IN_PROGRESS;
+			/*
+			 * In I2C_FUNC_SMBUS_BLOCK_DATA case, there is no data
+			 * to send before receiving data length from slave.
+			 * Disable TX_EMPTY while waiting for data length byte
+			 */
+			if (flags & I2C_M_RECV_LEN)
+				intr_mask &= ~DW_IC_INTR_TX_EMPTY;
 			break;
 		} else
 			dev->status &= ~STATUS_WRITE_IN_PROGRESS;
@@ -485,6 +492,7 @@ i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len)
 {
 	struct i2c_msg *msgs = dev->msgs;
 	u32 flags = msgs[dev->msg_read_idx].flags;
+	u32 intr_mask;
 
 	/*
 	 * Adjust the buffer length and mask the flag
@@ -495,6 +503,11 @@ 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;
 
+	/* Re-enable TX_EMPTY interrupt. */
+	regmap_read(dev->map, DW_IC_INTR_MASK, &intr_mask);
+	intr_mask |= DW_IC_INTR_TX_EMPTY;
+	regmap_write(dev->map, DW_IC_INTR_MASK, intr_mask);
+
 	return len;
 }
 
-- 
2.25.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ