diff mbox series

[v3] mmc: mmci: Add busydetect timeout

Message ID 20230518210246.2401737-1-linus.walleij@linaro.org (mailing list archive)
State New, archived
Headers show
Series [v3] mmc: mmci: Add busydetect timeout | expand

Commit Message

Linus Walleij May 18, 2023, 9:02 p.m. UTC
Add a timeout for busydetect IRQs using a delayed work.
It might happen (and does happen) on Ux500 that the first
busy detect IRQ appears and not the second one. This will
make the host hang indefinitely waiting for the second
IRQ to appear.

Fire a delayed work after 10ms and re-engage the command
IRQ so the transaction finishes: we are certainly done
at this point, or we will catch an error in the status
register.

This makes the eMMC work again on Skomer and Codina phones.

Notice that the hardware time-out cannot be used, because
the state machine in the MMCI will not see that something
is wrong.

Cc: stable@vger.kernel.org
Cc: phone-devel@vger.kernel.org
Cc: Stefan Hansson <newbyte@disroot.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
ChangeLog v2->v3:
- Took out the most urgent fix from the pile of changes
  and send separately, without the rest of the refactorings
  that were used for debugging the issue. After this the
  Skomer and Codina with problematic eMMC boots fine.
- Now just a single patch!
- This version should be easier to backport as well.
---
 drivers/mmc/host/mmci.c | 22 ++++++++++++++++++++++
 drivers/mmc/host/mmci.h |  1 +
 2 files changed, 23 insertions(+)

Comments

Linus Walleij May 22, 2023, 6:49 a.m. UTC | #1
On Thu, May 18, 2023 at 11:02 PM Linus Walleij <linus.walleij@linaro.org> wrote:

> ChangeLog v2->v3:
> - Took out the most urgent fix from the pile of changes
>   and send separately, without the rest of the refactorings
>   that were used for debugging the issue. After this the
>   Skomer and Codina with problematic eMMC boots fine.

Scratch this, while this gets the phones to boot it does not make
the eMMC partitions mountable. When I try to balance the
scheduled timeout with cancelling of the delayed work things
screw up as well, so I need to progress with the "big" patch
series, some of the other issues is coming into play as
well as it seems..

Yours,
Linus Walleij
diff mbox series

Patch

diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index f2b2e8b0574e..f3349fb99590 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -37,6 +37,7 @@ 
 #include <linux/pinctrl/consumer.h>
 #include <linux/reset.h>
 #include <linux/gpio/consumer.h>
+#include <linux/workqueue.h>
 
 #include <asm/div64.h>
 #include <asm/io.h>
@@ -695,6 +696,8 @@  static bool ux500_busy_complete(struct mmci_host *host, u32 status, u32 err_msk)
 	if (host->busy_status &&
 	    (status & host->variant->busy_detect_flag)) {
 		writel(host->variant->busy_detect_mask, base + MMCICLEAR);
+		schedule_delayed_work(&host->busy_timeout_work,
+				      msecs_to_jiffies(10));
 		return false;
 	}
 
@@ -1429,6 +1432,22 @@  mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
 	}
 }
 
+/*
+ * This busy timeout worker is used to "kick" the command IRQ if a
+ * busy detect IRQ fails to appear in reasonable time. Only used on
+ * variants with busy detection IRQ delivery.
+ */
+static void busy_timeout_work(struct work_struct *work)
+{
+        struct mmci_host *host =
+		container_of(work, struct mmci_host, busy_timeout_work.work);
+	u32 status;
+
+	dev_dbg(mmc_dev(host->mmc), "timeout waiting for busy IRQ\n");
+	status = readl(host->base + MMCISTATUS);
+	mmci_cmd_irq(host, host->cmd, status);
+}
+
 static int mmci_get_rx_fifocnt(struct mmci_host *host, u32 status, int remain)
 {
 	return remain - (readl(host->base + MMCIFIFOCNT) << 2);
@@ -2242,6 +2261,9 @@  static int mmci_probe(struct amba_device *dev,
 			goto clk_disable;
 	}
 
+	if (host->variant->busy_detect && host->ops->busy_complete)
+		INIT_DELAYED_WORK(&host->busy_timeout_work, busy_timeout_work);
+
 	writel(MCI_IRQENABLE | variant->start_err, host->base + MMCIMASK0);
 
 	amba_set_drvdata(dev, mmc);
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index e1a9b96a3396..de2c1436f4cd 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -437,6 +437,7 @@  struct mmci_host {
 	void			*dma_priv;
 
 	s32			next_cookie;
+	struct delayed_work	busy_timeout_work;
 };
 
 #define dma_inprogress(host)	((host)->dma_in_progress)