diff options
| author | Przemyslaw Marczak <p.marczak@samsung.com> | 2013-10-08 18:12:09 +0200 | 
|---|---|---|
| committer | Pantelis Antoniou <panto@antoniou-consulting.com> | 2013-10-31 09:55:33 +0200 | 
| commit | 56b34bc617f64ce34b34cebc7cbde7a8e4c1002f (patch) | |
| tree | d9716cee9cc8083c8a6194284c0518f81d5dcf0e /drivers/mmc/sdhci.c | |
| parent | b44fe83a580c21082486931367277c02d48c6469 (diff) | |
| download | olio-uboot-2014.01-56b34bc617f64ce34b34cebc7cbde7a8e4c1002f.tar.xz olio-uboot-2014.01-56b34bc617f64ce34b34cebc7cbde7a8e4c1002f.zip | |
mmc: sdhci: Avoid commands errors by simple timeout adaptation.
Old command timeout value was too small and it caused I/O errors which
led to uncompleted read/write/erase operations and filesystem errors.
Timeout adaptation fixes this issue.
Changes in sdhci_send_command() function:
- change timeout variable to static
- increase default command timeout to 100 ms
- add definition of max command timeout value,
  which can be redefined in each board config file
- wait for card ready state for max defined time
  if it doesn't exceed defined maximum or return COMM_ERR
Once successfully increased timeout value will be used in next function
call. This fix was tested on Goni, Trats, Trats2 boards by testing UMS
on MMC storage.
Changes v2:
- move global variable cmd_timeout into function sdhci_send_command()
- change condition "==" to ">=" when comparing time with timeout
- print information about timeout increasing and card busy timeout
Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
Cc: Pantelis Antoniou <panto@antoniou-consulting.com>
Diffstat (limited to 'drivers/mmc/sdhci.c')
| -rw-r--r-- | drivers/mmc/sdhci.c | 35 | 
1 files changed, 28 insertions, 7 deletions
| diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index dfb2eeeb4..46ae9cb52 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -109,6 +109,19 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data,  	return 0;  } +/* + * No command will be sent by driver if card is busy, so driver must wait + * for card ready state. + * Every time when card is busy after timeout then (last) timeout value will be + * increased twice but only if it doesn't exceed global defined maximum. + * Each function call will use last timeout value. Max timeout can be redefined + * in board config file. + */ +#ifndef CONFIG_SDHCI_CMD_MAX_TIMEOUT +#define CONFIG_SDHCI_CMD_MAX_TIMEOUT		3200 +#endif +#define CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT	100 +  int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,  		       struct mmc_data *data)  { @@ -117,11 +130,12 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,  	int ret = 0;  	int trans_bytes = 0, is_aligned = 1;  	u32 mask, flags, mode; -	unsigned int timeout, start_addr = 0; +	unsigned int time = 0, start_addr = 0;  	unsigned int retry = 10000; +	int mmc_dev = mmc->block_dev.dev; -	/* Wait max 10 ms */ -	timeout = 10; +	/* Timeout unit - ms */ +	static unsigned int cmd_timeout = CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT;  	sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS);  	mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT; @@ -132,11 +146,18 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,  		mask &= ~SDHCI_DATA_INHIBIT;  	while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { -		if (timeout == 0) { -			printf("Controller never released inhibit bit(s).\n"); -			return COMM_ERR; +		if (time >= cmd_timeout) { +			printf("MMC: %d busy ", mmc_dev); +			if (2 * cmd_timeout <= CONFIG_SDHCI_CMD_MAX_TIMEOUT) { +				cmd_timeout += cmd_timeout; +				printf("timeout increasing to: %u ms.\n", +				       cmd_timeout); +			} else { +				puts("timeout.\n"); +				return COMM_ERR; +			}  		} -		timeout--; +		time++;  		udelay(1000);  	} |