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

Commit c8afc9d5 authored by Russell King's avatar Russell King
Browse files

ARM: mmci: avoid reporting too many completed bytes on fifo overrun



The data counter counts the number of bytes transferred on the MMC bus.
When a FIFO overrun occurs, we will not have transferred a FIFOs-worth
of data to memory, and so the data counter will be a FIFOs-worth ahead.
If this occurs on a block boundary, we will report one too many sectors
as successful.  Fix this.

Acked-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 613b152c
Loading
Loading
Loading
Loading
+18 −6
Original line number Original line Diff line number Diff line
@@ -283,22 +283,34 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
	if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
	if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
		u32 remain, success;
		u32 remain, success;


		/* Calculate how far we are into the transfer */
		/*
		 * Calculate how far we are into the transfer.  Note that
		 * the data counter gives the number of bytes transferred
		 * on the MMC bus, not on the host side.  On reads, this
		 * can be as much as a FIFO-worth of data ahead.  This
		 * matters for FIFO overruns only.
		 */
		remain = readl(host->base + MMCIDATACNT);
		remain = readl(host->base + MMCIDATACNT);
		success = data->blksz * data->blocks - remain;
		success = data->blksz * data->blocks - remain;


		dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status);
		dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ, status 0x%08x at 0x%08x\n",
			status, success);
		if (status & MCI_DATACRCFAIL) {
		if (status & MCI_DATACRCFAIL) {
			/* Last block was not successful */
			/* Last block was not successful */
			host->data_xfered = round_down(success - 1, data->blksz);
			success -= 1;
			data->error = -EILSEQ;
			data->error = -EILSEQ;
		} else if (status & MCI_DATATIMEOUT) {
		} else if (status & MCI_DATATIMEOUT) {
			host->data_xfered = round_down(success, data->blksz);
			data->error = -ETIMEDOUT;
			data->error = -ETIMEDOUT;
		} else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
		} else if (status & MCI_TXUNDERRUN) {
			host->data_xfered = round_down(success, data->blksz);
			data->error = -EIO;
		} else if (status & MCI_RXOVERRUN) {
			if (success > host->variant->fifosize)
				success -= host->variant->fifosize;
			else
				success = 0;
			data->error = -EIO;
			data->error = -EIO;
		}
		}
		host->data_xfered = round_down(success, data->blksz);


		/*
		/*
		 * We hit an error condition.  Ensure that any data
		 * We hit an error condition.  Ensure that any data