mtd: mxc-nand: Add a timeout when waiting for interrupt

Linux-MTD Mailing List linux-mtd at lists.infradead.org
Wed Apr 22 10:59:02 PDT 2015


Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=e35d1d8a1d16e9f56a9b54c96d0cb85ed621bb89
Commit:     e35d1d8a1d16e9f56a9b54c96d0cb85ed621bb89
Parent:     111573ccd89b67fdef64d945cc0e611df85a6ac8
Author:     Uwe Kleine-König <u.kleine-koenig at pengutronix.de>
AuthorDate: Tue Feb 10 19:59:55 2015 +0100
Committer:  Brian Norris <computersforpeace at gmail.com>
CommitDate: Wed Mar 11 15:20:11 2015 -0700

    mtd: mxc-nand: Add a timeout when waiting for interrupt
    
    While extending the mxc-nand driver it happend to me a few times that
    the device was stuck and this made the machine hang during boot. So
    implement a timeout and print a stack trace the first time this happens
    to make it debuggable. The return type of the waiting function is also
    changed to int to be able to handle the timeout in the caller.
    
    Signed-off-by: Uwe Kleine-König <u.kleine-koenig at pengutronix.de>
    Signed-off-by: Brian Norris <computersforpeace at gmail.com>
---
 drivers/mtd/nand/mxc_nand.c | 47 ++++++++++++++++++++++++++++++++++-----------
 1 file changed, 36 insertions(+), 11 deletions(-)

diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index a8f550f..27ba07c 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -386,26 +386,51 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
 /* This function polls the NANDFC to wait for the basic operation to
  * complete by checking the INT bit of config2 register.
  */
-static void wait_op_done(struct mxc_nand_host *host, int useirq)
+static int wait_op_done(struct mxc_nand_host *host, int useirq)
 {
-	int max_retries = 8000;
+	int ret = 0;
+
+	/*
+	 * If operation is already complete, don't bother to setup an irq or a
+	 * loop.
+	 */
+	if (host->devtype_data->check_int(host))
+		return 0;
 
 	if (useirq) {
-		if (!host->devtype_data->check_int(host)) {
-			reinit_completion(&host->op_completion);
-			irq_control(host, 1);
-			wait_for_completion(&host->op_completion);
+		unsigned long timeout;
+
+		reinit_completion(&host->op_completion);
+
+		irq_control(host, 1);
+
+		timeout = wait_for_completion_timeout(&host->op_completion, HZ);
+		if (!timeout && !host->devtype_data->check_int(host)) {
+			dev_dbg(host->dev, "timeout waiting for irq\n");
+			ret = -ETIMEDOUT;
 		}
 	} else {
-		while (max_retries-- > 0) {
-			if (host->devtype_data->check_int(host))
-				break;
+		int max_retries = 8000;
+		int done;
 
+		do {
 			udelay(1);
+
+			done = host->devtype_data->check_int(host);
+			if (done)
+				break;
+
+		} while (--max_retries);
+
+		if (!done) {
+			dev_dbg(host->dev, "timeout polling for completion\n");
+			ret = -ETIMEDOUT;
 		}
-		if (max_retries < 0)
-			pr_debug("%s: INT not set\n", __func__);
 	}
+
+	WARN_ONCE(ret < 0, "timeout! useirq=%d\n", useirq);
+
+	return ret;
 }
 
 static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq)



More information about the linux-mtd-cvs mailing list