diff mbox

[RFC,2/2] i2c: omap: show that the reason of system lockup is an unhandled ISR event

Message ID 1417294803-14729-3-git-send-email-al.kochet@gmail.com
State RFC
Headers show

Commit Message

Alexander Kochetkov Nov. 29, 2014, 9 p.m. UTC
Commit 079d8af24b948261e1dae5d7df6b31b7bf205cb4 ("i2c: omap: bus:
add a receiver flag") changed ISR loop to silently ignore unwanted
XDR/XRDY or RDR/RRDY events without processing. That unwanted events
will fire interrupt again and most likely they will be ignored again.
As a result, system enters lockup state. CPU loops through omap_i2c_isr()
and omap_i2c_isr_thread(). The lockup is signaled with the message
"sched: RT throttling activated" shown on console.

The commit allow unwanted events to enter into processing loop and
to be acked (at least) and processed (show error message).
Sometimes if unwannted event is acked, the ISR can continue it's work.
Sometimes system still remains in the lockup, but at least the reason
is obvious.

That unwanted events I tested with are events from IP slave receiver,
fired when General Call (GC) command is detected on the bus. As after
every master transfer IP enter into slave receiver mode. ISR must be
ready for events from slave receiver or slave receiver must be
disabled after master transfer to avoid lockups.

Signed-off-by: Alexander Kochetkov <al.kochet@gmail.com>
Fixes 079d8af24b948261e1dae5d7df6b31b7bf205cb4 "i2c: omap: bus: add a receiver flag"
---
 drivers/i2c/busses/i2c-omap.c |   28 ++++++++++++++++++++++------
 1 file changed, 22 insertions(+), 6 deletions(-)
diff mbox

Patch

diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index e890295..192f9ce 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -939,6 +939,22 @@  static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes,
 		bool is_rdr)
 {
 	u16 w;
+	int warn = 0;
+
+	if (unlikely(!dev->receiver)) {
+		warn = 1;
+		/* REVISIT: errata i207 during transmission? */
+		if (dev->errata & I2C_OMAP_ERRATA_I207) {
+			if (is_rdr & !num_bytes)
+				warn = 0;
+		}
+		num_bytes = 0;
+	}
+
+	if (unlikely(warn)) {
+		dev_err(dev->dev, "%s interrupt while sending\n",
+			is_rdr ? "RDR" : "RRDY");
+	}
 
 	if (unlikely(num_bytes > dev->buf_len)) {
 		dev_err(dev->dev, "%s interrupt can't receive %u byte(s)\n",
@@ -971,6 +987,12 @@  static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes,
 {
 	u16 w;
 
+	if (unlikely(dev->receiver)) {
+		dev_err(dev->dev, "%s interrupt while receiving\n",
+			is_xdr ? "XDR" : "XRDY");
+		num_bytes = 0;
+	}
+
 	if (unlikely(num_bytes > dev->buf_len)) {
 		dev_err(dev->dev, "%s interrupt can't transmit %u byte(s)\n",
 			is_xdr ? "XDR" : "XRDY", (num_bytes - dev->buf_len));
@@ -1043,12 +1065,6 @@  omap_i2c_isr_thread(int this_irq, void *dev_id)
 		stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
 		stat &= bits;
 
-		/* If we're in receiver mode, ignore XDR/XRDY */
-		if (dev->receiver)
-			stat &= ~(OMAP_I2C_STAT_XDR | OMAP_I2C_STAT_XRDY);
-		else
-			stat &= ~(OMAP_I2C_STAT_RDR | OMAP_I2C_STAT_RRDY);
-
 		if (!stat) {
 			/* my work here is done */
 			goto out;