Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 061c6c84 authored by Sonic Zhang's avatar Sonic Zhang Committed by Chris Ball
Browse files

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: default avatarSonic Zhang <sonic.zhang@analog.com>
Signed-off-by: default avatarMike Frysinger <vapier@gentoo.org>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent 95f25efe
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -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