aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorSonic Zhang <sonic.zhang@analog.com>2010-07-12 15:50:56 +0800
committerChris Ball <cjb@laptop.org>2010-10-23 21:11:22 +0800
commit061c6c847eeb11743e489a16e907b41c6f9042b6 (patch)
tree37bb835b50342cc459366e36da1117b137760f6d /drivers/mmc
parent95f25efe0ce22e28d61722d655d2ef582f5f7520 (diff)
downloadkernel_samsung_smdk4412-061c6c847eeb11743e489a16e907b41c6f9042b6.zip
kernel_samsung_smdk4412-061c6c847eeb11743e489a16e907b41c6f9042b6.tar.gz
kernel_samsung_smdk4412-061c6c847eeb11743e489a16e907b41c6f9042b6.tar.bz2
mmc_spi: Recover from CRC errors for r/w operation over SPI.
The SPI bus is not reliable for large data transfers on all platforms. The current mmc_spi driver fails SD read/write commands immediately if occasional CRC errors are reported by the SD device. This patch makes the operation recover from CRC errors by repeating the last SD command. The retry count is set to 5 to ensure the driver passes stress tests. Signed-off-by: Sonic Zhang <sonic.zhang@analog.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/mmc_spi.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index 5b0b506..fd877f6 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -1055,6 +1055,8 @@ static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct mmc_spi_host *host = mmc_priv(mmc);
int status = -EINVAL;
+ int crc_retry = 5;
+ struct mmc_command stop;
#ifdef DEBUG
/* MMC core and layered drivers *MUST* issue SPI-aware commands */
@@ -1087,10 +1089,29 @@ static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq)
/* request exclusive bus access */
spi_bus_lock(host->spi->master);
+crc_recover:
/* issue command; then optionally data and stop */
status = mmc_spi_command_send(host, mrq, mrq->cmd, mrq->data != NULL);
if (status == 0 && mrq->data) {
mmc_spi_data_do(host, mrq->cmd, mrq->data, mrq->data->blksz);
+
+ /*
+ * The SPI bus is not always reliable for large data transfers.
+ * If an occasional crc error is reported by the SD device with
+ * data read/write over SPI, it may be recovered by repeating
+ * the last SD command again. The retry count is set to 5 to
+ * ensure the driver passes stress tests.
+ */
+ if (mrq->data->error == -EILSEQ && crc_retry) {
+ stop.opcode = MMC_STOP_TRANSMISSION;
+ stop.arg = 0;
+ stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+ status = mmc_spi_command_send(host, mrq, &stop, 0);
+ crc_retry--;
+ mrq->data->error = 0;
+ goto crc_recover;
+ }
+
if (mrq->stop)
status = mmc_spi_command_send(host, mrq, mrq->stop, 0);
else