diff mbox series

[U-Boot,1/4] mmc: dw_mmc: check fifo status with a timeout in fifo mode

Message ID 20180921085948.26975-2-heiko@sntech.de
State Accepted
Commit 05fa06b9606387ad4a65723d93a83b36a98d600b
Delegated to: Philipp Tomsich
Headers show
Series rockchip: allow rk3188 to boot from mmc devices | expand

Commit Message

Heiko Stuebner Sept. 21, 2018, 8:59 a.m. UTC
While trying to enable the dw_mmc on rk3188 I managed to confuse
and hang the dw_mmc controller into not delivering further data.
The fifo state never became ready and the driver was iterating in
the while loop reading 0-byte packets forever.

So inspired by how other implementations handle this, check the fifo-
state beforhand and add a timeout to catch any glaring fifo issues
without hanging uboot altogether.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/mmc/dw_mmc.c | 32 ++++++++++++++++++++++++++++++--
 include/dwmmc.h      |  2 ++
 2 files changed, 32 insertions(+), 2 deletions(-)

Comments

Philipp Tomsich Sept. 21, 2018, 9:16 a.m. UTC | #1
> On 21.09.2018, at 10:59, Heiko Stuebner <heiko@sntech.de> wrote:
> 
> While trying to enable the dw_mmc on rk3188 I managed to confuse
> and hang the dw_mmc controller into not delivering further data.
> The fifo state never became ready and the driver was iterating in
> the while loop reading 0-byte packets forever.
> 
> So inspired by how other implementations handle this, check the fifo-
> state beforhand and add a timeout to catch any glaring fifo issues
> without hanging uboot altogether.
> 
> Signed-off-by: Heiko Stuebner <heiko@sntech.de>

Reviewed-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
Acked-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
Philipp Tomsich Oct. 2, 2018, 2 p.m. UTC | #2
> While trying to enable the dw_mmc on rk3188 I managed to confuse
> and hang the dw_mmc controller into not delivering further data.
> The fifo state never became ready and the driver was iterating in
> the while loop reading 0-byte packets forever.
> 
> So inspired by how other implementations handle this, check the fifo-
> state beforhand and add a timeout to catch any glaring fifo issues
> without hanging uboot altogether.
> 
> Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> Reviewed-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
> Acked-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
> ---
>  drivers/mmc/dw_mmc.c | 32 ++++++++++++++++++++++++++++++--
>  include/dwmmc.h      |  2 ++
>  2 files changed, 32 insertions(+), 2 deletions(-)
> 

Applied to u-boot-rockchip, thanks!
diff mbox series

Patch

diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index 13180fc0d6..3c702b3ed8 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -92,6 +92,24 @@  static void dwmci_prepare_data(struct dwmci_host *host,
 	dwmci_writel(host, DWMCI_BYTCNT, data->blocksize * data->blocks);
 }
 
+static int dwmci_fifo_ready(struct dwmci_host *host, u32 bit, u32 *len)
+{
+	u32 timeout = 20000;
+
+	*len = dwmci_readl(host, DWMCI_STATUS);
+	while (--timeout && (*len & bit)) {
+		udelay(200);
+		*len = dwmci_readl(host, DWMCI_STATUS);
+	}
+
+	if (!timeout) {
+		debug("%s: FIFO underflow timeout\n", __func__);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
 static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
 {
 	int ret = 0;
@@ -122,7 +140,12 @@  static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
 			if (data->flags == MMC_DATA_READ &&
 			    (mask & DWMCI_INTMSK_RXDR)) {
 				while (size) {
-					len = dwmci_readl(host, DWMCI_STATUS);
+					ret = dwmci_fifo_ready(host,
+							DWMCI_FIFO_EMPTY,
+							&len);
+					if (ret < 0)
+						break;
+
 					len = (len >> DWMCI_FIFO_SHIFT) &
 						    DWMCI_FIFO_MASK;
 					len = min(size, len);
@@ -136,7 +159,12 @@  static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
 			} else if (data->flags == MMC_DATA_WRITE &&
 				   (mask & DWMCI_INTMSK_TXDR)) {
 				while (size) {
-					len = dwmci_readl(host, DWMCI_STATUS);
+					ret = dwmci_fifo_ready(host,
+							DWMCI_FIFO_FULL,
+							&len);
+					if (ret < 0)
+						break;
+
 					len = fifo_depth - ((len >>
 						   DWMCI_FIFO_SHIFT) &
 						   DWMCI_FIFO_MASK);
diff --git a/include/dwmmc.h b/include/dwmmc.h
index bc1d6e3abb..0f9d51b557 100644
--- a/include/dwmmc.h
+++ b/include/dwmmc.h
@@ -103,6 +103,8 @@ 
 #define DWMCI_CTYPE_8BIT	(1 << 16)
 
 /* Status Register */
+#define DWMCI_FIFO_EMPTY	(1 << 2)
+#define DWMCI_FIFO_FULL		(1 << 3)
 #define DWMCI_BUSY		(1 << 9)
 #define DWMCI_FIFO_MASK		0x1fff
 #define DWMCI_FIFO_SHIFT	17