mtd: mxc-nand: Add a timeout when waiting for interrupt
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Tue, 10 Feb 2015 18:59:55 +0000 (19:59 +0100)
committerBrian Norris <computersforpeace@gmail.com>
Wed, 11 Mar 2015 22:20:11 +0000 (15:20 -0700)
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@pengutronix.de>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
drivers/mtd/nand/mxc_nand.c

index a8f550fec35e009932f4cb5d5cff9e0df17fd2b4..27ba07c079661380e4b662a30151a2ded964dd9c 100644 (file)
@@ -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)