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-prev] [thread-next>] [day] [month] [year] [list]
Date:	Thu, 17 Jan 2013 12:31:05 +0200
From:	Mika Westerberg <mika.westerberg@...ux.intel.com>
To:	linux-i2c@...r.kernel.org
Cc:	Wolfram Sang <w.sang@...gutronix.de>,
	"Ben Dooks (embedded platforms)" <ben-linux@...ff.org>,
	Jean Delvare <khali@...ux-fr.org>,
	Mika Westerberg <mika.westerberg@...ux.intel.com>,
	dirk.brandewie@...il.com, linux-kernel@...r.kernel.org
Subject: [PATCH 2/4] i2c-designware: always set the STOP bit after last byte

If IC_EMPTYFIFO_HOLD_MASTER_EN is set to one, the DesignWare I2C controller
doesn't generate STOP on the bus when the FIFO is empty. This violates the
rules of Linux I2C stack as it requires that the STOP is issued once the
i2c_transfer() is finished.

However, there is no way to detect this from the hardware registers, so we
must make sure that the STOP bit is always set once the last byte of the
last message is transferred.

This patch is based on the work of Dirk Brandewie.

Signed-off-by: Mika Westerberg <mika.westerberg@...ux.intel.com>
---
 drivers/i2c/busses/i2c-designware-core.c |   16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index f5258c2..94fd818 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -413,11 +413,23 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
 		rx_limit = dev->rx_fifo_depth - dw_readl(dev, DW_IC_RXFLR);
 
 		while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) {
+			u32 cmd = 0;
+
+			/*
+			 * If IC_EMPTYFIFO_HOLD_MASTER_EN is set we must
+			 * manually set the stop bit. However, it cannot be
+			 * detected from the registers so we set it always
+			 * when writing/reading the last byte.
+			 */
+			if (dev->msg_write_idx == dev->msgs_num - 1 &&
+			    buf_len == 1)
+				cmd |= BIT(9);
+
 			if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
-				dw_writel(dev, 0x100, DW_IC_DATA_CMD);
+				dw_writel(dev, cmd | 0x100, DW_IC_DATA_CMD);
 				rx_limit--;
 			} else
-				dw_writel(dev, *buf++, DW_IC_DATA_CMD);
+				dw_writel(dev, cmd | *buf++, DW_IC_DATA_CMD);
 			tx_limit--; buf_len--;
 		}
 
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ