[U-Boot] [PATCH v2] mmc: omap: timeout counter fix

Nishanth Menon nm at ti.com
Tue Oct 26 03:02:04 CEST 2010


Having a loop with a counter is no timing guarentee for timing
accuracy or compiler optimizations. For e.g. the same loop counter
which runs when the MPU is running at 600MHz will timeout in around
half the time when running at 1GHz. or the example where GCC 4.5
compiles with different optimization compared to GCC 4.4.
use a udelay(10) to ensure we have a predictable delay.
use an emperical number - 100000 uSec ~= 1sec for a worst case timeout.
This should never happen, and is adequate imaginary condition for us
to fail with timeout.

Signed-off-by: Nishanth Menon <nm at ti.com>
---
V2: additional cleanups + made MAX_RETRY a macro for reuse throughout
the file. tested on PandaBoard with 1GHz boot frequency and GCC4.5 on
u-boot 2010.09 + mmc patches. Requesting testing on other platforms

V1: http://www.mail-archive.com/u-boot@lists.denx.de/msg40969.html

 drivers/mmc/omap_hsmmc.c |  114 +++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 97 insertions(+), 17 deletions(-)

diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
index 9271470..f7bdfe9 100644
--- a/drivers/mmc/omap_hsmmc.c
+++ b/drivers/mmc/omap_hsmmc.c
@@ -30,6 +30,7 @@
 #include <twl4030.h>
 #include <asm/io.h>
 #include <asm/arch/mmc_host_def.h>
+#define MAX_RETRY	100000
 
 static int mmc_read_data(hsmmc_t *mmc_base, char *buf, unsigned int size);
 static int mmc_write_data(hsmmc_t *mmc_base, const char *buf, unsigned int siz);
@@ -70,18 +71,32 @@ unsigned char mmc_board_init(hsmmc_t *mmc_base)
 
 void mmc_init_stream(hsmmc_t *mmc_base)
 {
+	int retry = MAX_RETRY;
 
 	writel(readl(&mmc_base->con) | INIT_INITSTREAM, &mmc_base->con);
 
 	writel(MMC_CMD0, &mmc_base->cmd);
-	while (!(readl(&mmc_base->stat) & CC_MASK))
-		;
+	while (!(readl(&mmc_base->stat) & CC_MASK)) {
+		retry--;
+		udelay(10);
+		if (!retry) {
+			printf("%s: timedout waiting for cc!\n", __func__);
+			return;
+		}
+	}
 	writel(CC_MASK, &mmc_base->stat)
 		;
 	writel(MMC_CMD0, &mmc_base->cmd)
 		;
-	while (!(readl(&mmc_base->stat) & CC_MASK))
-		;
+	retry = MAX_RETRY;
+	while (!(readl(&mmc_base->stat) & CC_MASK)) {
+		retry--;
+		udelay(10);
+		if (!retry) {
+			printf("%s: timedout waiting for cc2!\n", __func__);
+			return;
+		}
+	}
 	writel(readl(&mmc_base->con) & ~INIT_INITSTREAM, &mmc_base->con);
 }
 
@@ -91,16 +106,31 @@ static int mmc_init_setup(struct mmc *mmc)
 	hsmmc_t *mmc_base = (hsmmc_t *)mmc->priv;
 	unsigned int reg_val;
 	unsigned int dsor;
+	int retry = MAX_RETRY;
 
 	mmc_board_init(mmc_base);
 
 	writel(readl(&mmc_base->sysconfig) | MMC_SOFTRESET,
 		&mmc_base->sysconfig);
-	while ((readl(&mmc_base->sysstatus) & RESETDONE) == 0)
-		;
+	while ((readl(&mmc_base->sysstatus) & RESETDONE) == 0) {
+		retry--;
+		udelay(10);
+		if (!retry) {
+			printf("%s: timedout waiting for cc2!\n", __func__);
+			return TIMEOUT;
+		}
+	}
 	writel(readl(&mmc_base->sysctl) | SOFTRESETALL, &mmc_base->sysctl);
-	while ((readl(&mmc_base->sysctl) & SOFTRESETALL) != 0x0)
-		;
+	retry = MAX_RETRY;
+	while ((readl(&mmc_base->sysctl) & SOFTRESETALL) != 0x0) {
+		retry--;
+		udelay(10);
+		if (!retry) {
+			printf("%s: timedout waiting for softresetall!\n",
+				__func__);
+			return TIMEOUT;
+		}
+	}
 	writel(DTW_1_BITMODE | SDBP_PWROFF | SDVS_3V0, &mmc_base->hctl);
 	writel(readl(&mmc_base->capa) | VS30_3V0SUP | VS18_1V8SUP,
 		&mmc_base->capa);
@@ -116,8 +146,15 @@ static int mmc_init_setup(struct mmc *mmc)
 		(ICE_STOP | DTO_15THDTO | CEN_DISABLE));
 	mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
 		(dsor << CLKD_OFFSET) | ICE_OSCILLATE);
-	while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY)
-		;
+	retry = MAX_RETRY;
+	while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
+		retry--;
+		udelay(10);
+		if (!retry) {
+			printf("%s: timedout waiting for ics!\n", __func__);
+			return TIMEOUT;
+		}
+	}
 	writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
 
 	writel(readl(&mmc_base->hctl) | SDBP_PWRON, &mmc_base->hctl);
@@ -137,14 +174,27 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
 {
 	hsmmc_t *mmc_base = (hsmmc_t *)mmc->priv;
 	unsigned int flags, mmc_stat;
-	unsigned int retry = 0x100000;
+	int retry = MAX_RETRY;
 
 
-	while ((readl(&mmc_base->pstate) & DATI_MASK) == DATI_CMDDIS)
-		;
+	while ((readl(&mmc_base->pstate) & DATI_MASK) == DATI_CMDDIS) {
+		retry--;
+		udelay(10);
+		if (!retry) {
+			printf("%s: timedout waiting for cmddis!\n", __func__);
+			return TIMEOUT;
+		}
+	}
 	writel(0xFFFFFFFF, &mmc_base->stat);
-	while (readl(&mmc_base->stat))
-		;
+	retry = MAX_RETRY;
+	while (readl(&mmc_base->stat)) {
+		retry--;
+		udelay(10);
+		if (!retry) {
+			printf("%s: timedout waiting for stat!\n", __func__);
+			return TIMEOUT;
+		}
+	}
 	/*
 	 * CMDREG
 	 * CMDIDX[13:8]	: Command index
@@ -200,8 +250,11 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
 	writel(cmd->cmdarg, &mmc_base->arg);
 	writel((cmd->cmdidx << 24) | flags, &mmc_base->cmd);
 
+	retry = MAX_RETRY;
 	do {
 		mmc_stat = readl(&mmc_base->stat);
+		if (!mmc_stat)
+			udelay(10);
 		retry--;
 	} while ((mmc_stat == 0) && (retry > 0));
 
@@ -253,8 +306,18 @@ static int mmc_read_data(hsmmc_t *mmc_base, char *buf, unsigned int size)
 	count /= 4;
 
 	while (size) {
+		int retry = MAX_RETRY;
 		do {
 			mmc_stat = readl(&mmc_base->stat);
+			if (!mmc_stat) {
+				retry--;
+				udelay(10);
+			}
+			if (!retry) {
+				printf("%s: timedout waiting for status!\n",
+						__func__);
+				return TIMEOUT;
+			}
 		} while (mmc_stat == 0);
 
 		if ((mmc_stat & ERRI_MASK) != 0)
@@ -298,8 +361,18 @@ static int mmc_write_data(hsmmc_t *mmc_base, const char *buf, unsigned int size)
 	count /= 4;
 
 	while (size) {
+		int retry = MAX_RETRY;
 		do {
 			mmc_stat = readl(&mmc_base->stat);
+			if (!mmc_stat) {
+				retry--;
+				udelay(10);
+			}
+			if (!retry) {
+				printf("%s: timedout waiting for status!\n",
+						__func__);
+				return TIMEOUT;
+			}
 		} while (mmc_stat == 0);
 
 		if ((mmc_stat & ERRI_MASK) != 0)
@@ -334,6 +407,7 @@ static void mmc_set_ios(struct mmc *mmc)
 {
 	hsmmc_t *mmc_base = (hsmmc_t *)mmc->priv;
 	unsigned int dsor = 0;
+	int retry = MAX_RETRY;
 
 	/* configue bus width */
 	switch (mmc->bus_width) {
@@ -372,8 +446,14 @@ static void mmc_set_ios(struct mmc *mmc)
 	mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
 				(dsor << CLKD_OFFSET) | ICE_OSCILLATE);
 
-	while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY)
-		;
+	while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
+		retry--;
+		udelay(10);
+		if (!retry) {
+			printf("%s: timedout waiting for ics!\n", __func__);
+			return;
+		}
+	}
 	writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
 }
 
-- 
1.6.3.3



More information about the U-Boot mailing list