1
0
Fork 0

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>
hifive-unleashed-5.1
Sonic Zhang 2010-07-12 15:50:56 +08:00 committed by Chris Ball
parent 95f25efe0c
commit 061c6c847e
1 changed files with 21 additions and 0 deletions

View File

@ -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