[PATCH] mmc: dw_mmc: Fix FIFO data transfer timeout

Jonas Karlman jonas at kwiboo.se
Tue Oct 8 02:35:00 CEST 2024


The commit 0252924ac6d4 ("mmc: dw_mmc: Extract FIFO data transfer into a
separate routine") unintentionally changed behavior of the FIFO data
transfer routine.

When data is read and size reaches 0 the original loop would wait on
DWMCI_INTMSK_DTO or timeout. The remaining size to read is no longer
tracked across dwmci_data_transfer_fifo() calls and because of this an
extra call to fifo() and dwmci_fifo_ready() may now trigger a FIFO
underflow timeout.

  Buswidth = 4, clock: 50000000
  Sending CMD16
  Sending CMD17
  dwmci_fifo_ready: FIFO underflow timeout
  Sending CMD16
  Sending CMD18
  dwmci_fifo_ready: FIFO underflow timeout
  Sending CMD12
  ## Checking hash(es) for config config-1 ... OK

Restore old behavior and track remaining size to read across calls to
fix this.

Fixes: 0252924ac6d4 ("mmc: dw_mmc: Extract FIFO data transfer into a separate routine")
Signed-off-by: Jonas Karlman <jonas at kwiboo.se>
---
Reading FIT from SD-card take ~20-30 seconds on a Rockchip RK3328 board
without this fixed, and goes back to sub second once fixed.
---
 drivers/mmc/dw_mmc.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index 8551eac70185..98b85fd1795a 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -214,16 +214,15 @@ static unsigned int dwmci_get_timeout(struct mmc *mmc, const unsigned int size)
 	return timeout;
 }
 
-static int dwmci_data_transfer_fifo(struct dwmci_host *host,
-				    struct mmc_data *data, u32 mask)
+static u32 dwmci_data_transfer_fifo(struct dwmci_host *host,
+				    struct mmc_data *data, u32 size, u32 mask)
 {
 	const u32 int_rx = mask & (DWMCI_INTMSK_RXDR | DWMCI_INTMSK_DTO);
 	const u32 int_tx = mask & DWMCI_INTMSK_TXDR;
 	int ret = 0;
-	u32 len = 0, size, i;
+	u32 len = 0, i;
 	u32 *buf;
 
-	size = (data->blocksize * data->blocks) / 4;
 	if (!host->fifo_mode || !size)
 		return 0;
 
@@ -261,7 +260,7 @@ static int dwmci_data_transfer_fifo(struct dwmci_host *host,
 		dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_TXDR);
 	}
 
-	return ret;
+	return size;
 }
 
 static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
@@ -273,6 +272,7 @@ static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
 
 	size = data->blocksize * data->blocks;
 	timeout = dwmci_get_timeout(mmc, size);
+	size /= 4;
 
 	for (;;) {
 		mask = dwmci_readl(host, DWMCI_RINTSTS);
@@ -283,7 +283,7 @@ static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
 			break;
 		}
 
-		ret = dwmci_data_transfer_fifo(host, data, mask);
+		size = dwmci_data_transfer_fifo(host, data, size, mask);
 
 		/* Data arrived correctly */
 		if (mask & DWMCI_INTMSK_DTO) {
-- 
2.46.2



More information about the U-Boot mailing list