Commit efe8f5c9 authored by Shaik Sajida Bhanu's avatar Shaik Sajida Bhanu Committed by Ulf Hansson
Browse files

mmc: sdhci: Capture eMMC and SD card errors

parent 91f059c9
Loading
Loading
Loading
Loading
+44 −15
Original line number Diff line number Diff line
@@ -224,6 +224,7 @@ void sdhci_reset(struct sdhci_host *host, u8 mask)
		if (timedout) {
			pr_err("%s: Reset 0x%x never completed.\n",
				mmc_hostname(host->mmc), (int)mask);
			sdhci_err_stats_inc(host, CTRL_TIMEOUT);
			sdhci_dumpregs(host);
			return;
		}
@@ -1716,6 +1717,7 @@ static bool sdhci_send_command_retry(struct sdhci_host *host,
		if (!timeout--) {
			pr_err("%s: Controller never released inhibit bit(s).\n",
			       mmc_hostname(host->mmc));
			sdhci_err_stats_inc(host, CTRL_TIMEOUT);
			sdhci_dumpregs(host);
			cmd->error = -EIO;
			return false;
@@ -1965,6 +1967,7 @@ void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
		if (timedout) {
			pr_err("%s: Internal clock never stabilised.\n",
			       mmc_hostname(host->mmc));
			sdhci_err_stats_inc(host, CTRL_TIMEOUT);
			sdhci_dumpregs(host);
			return;
		}
@@ -1987,6 +1990,7 @@ void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
			if (timedout) {
				pr_err("%s: PLL clock never stabilised.\n",
				       mmc_hostname(host->mmc));
				sdhci_err_stats_inc(host, CTRL_TIMEOUT);
				sdhci_dumpregs(host);
				return;
			}
@@ -3161,6 +3165,7 @@ static void sdhci_timeout_timer(struct timer_list *t)
	if (host->cmd && !sdhci_data_line_cmd(host->cmd)) {
		pr_err("%s: Timeout waiting for hardware cmd interrupt.\n",
		       mmc_hostname(host->mmc));
		sdhci_err_stats_inc(host, REQ_TIMEOUT);
		sdhci_dumpregs(host);

		host->cmd->error = -ETIMEDOUT;
@@ -3183,6 +3188,7 @@ static void sdhci_timeout_data_timer(struct timer_list *t)
	    (host->cmd && sdhci_data_line_cmd(host->cmd))) {
		pr_err("%s: Timeout waiting for hardware interrupt.\n",
		       mmc_hostname(host->mmc));
		sdhci_err_stats_inc(host, REQ_TIMEOUT);
		sdhci_dumpregs(host);

		if (host->data) {
@@ -3234,17 +3240,21 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p)
			return;
		pr_err("%s: Got command interrupt 0x%08x even though no command operation was in progress.\n",
		       mmc_hostname(host->mmc), (unsigned)intmask);
		sdhci_err_stats_inc(host, UNEXPECTED_IRQ);
		sdhci_dumpregs(host);
		return;
	}

	if (intmask & (SDHCI_INT_TIMEOUT | SDHCI_INT_CRC |
		       SDHCI_INT_END_BIT | SDHCI_INT_INDEX)) {
		if (intmask & SDHCI_INT_TIMEOUT)
		if (intmask & SDHCI_INT_TIMEOUT) {
			host->cmd->error = -ETIMEDOUT;
		else
			sdhci_err_stats_inc(host, CMD_TIMEOUT);
		} else {
			host->cmd->error = -EILSEQ;

			if (!mmc_op_tuning(host->cmd->opcode))
				sdhci_err_stats_inc(host, CMD_CRC);
		}
		/* Treat data command CRC error the same as data CRC error */
		if (host->cmd->data &&
		    (intmask & (SDHCI_INT_CRC | SDHCI_INT_TIMEOUT)) ==
@@ -3266,6 +3276,8 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p)
			  -ETIMEDOUT :
			  -EILSEQ;

		sdhci_err_stats_inc(host, AUTO_CMD);

		if (sdhci_auto_cmd23(host, mrq)) {
			mrq->sbc->error = err;
			__sdhci_finish_mrq(host, mrq);
@@ -3342,6 +3354,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
			if (intmask & SDHCI_INT_DATA_TIMEOUT) {
				host->data_cmd = NULL;
				data_cmd->error = -ETIMEDOUT;
				sdhci_err_stats_inc(host, CMD_TIMEOUT);
				__sdhci_finish_mrq(host, data_cmd->mrq);
				return;
			}
@@ -3370,23 +3383,30 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)

		pr_err("%s: Got data interrupt 0x%08x even though no data operation was in progress.\n",
		       mmc_hostname(host->mmc), (unsigned)intmask);
		sdhci_err_stats_inc(host, UNEXPECTED_IRQ);
		sdhci_dumpregs(host);

		return;
	}

	if (intmask & SDHCI_INT_DATA_TIMEOUT)
	if (intmask & SDHCI_INT_DATA_TIMEOUT) {
		host->data->error = -ETIMEDOUT;
	else if (intmask & SDHCI_INT_DATA_END_BIT)
		sdhci_err_stats_inc(host, DAT_TIMEOUT);
	} else if (intmask & SDHCI_INT_DATA_END_BIT) {
		host->data->error = -EILSEQ;
	else if ((intmask & SDHCI_INT_DATA_CRC) &&
		if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
			sdhci_err_stats_inc(host, DAT_CRC);
	} else if ((intmask & SDHCI_INT_DATA_CRC) &&
		SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))
			!= MMC_BUS_TEST_R)
			!= MMC_BUS_TEST_R) {
		host->data->error = -EILSEQ;
	else if (intmask & SDHCI_INT_ADMA_ERROR) {
		if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
			sdhci_err_stats_inc(host, DAT_CRC);
	} else if (intmask & SDHCI_INT_ADMA_ERROR) {
		pr_err("%s: ADMA error: 0x%08x\n", mmc_hostname(host->mmc),
		       intmask);
		sdhci_adma_show_error(host);
		sdhci_err_stats_inc(host, ADMA);
		host->data->error = -EIO;
		if (host->ops->adma_workaround)
			host->ops->adma_workaround(host, intmask);
@@ -3584,6 +3604,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
	if (unexpected) {
		pr_err("%s: Unexpected interrupt 0x%08x.\n",
			   mmc_hostname(host->mmc), unexpected);
		sdhci_err_stats_inc(host, UNEXPECTED_IRQ);
		sdhci_dumpregs(host);
	}

@@ -3905,20 +3926,27 @@ bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error,
	if (!host->cqe_on)
		return false;

	if (intmask & (SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC))
	if (intmask & (SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC)) {
		*cmd_error = -EILSEQ;
	else if (intmask & SDHCI_INT_TIMEOUT)
		if (!mmc_op_tuning(host->cmd->opcode))
			sdhci_err_stats_inc(host, CMD_CRC);
	} else if (intmask & SDHCI_INT_TIMEOUT) {
		*cmd_error = -ETIMEDOUT;
	else
		sdhci_err_stats_inc(host, CMD_TIMEOUT);
	} else
		*cmd_error = 0;

	if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC))
	if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC)) {
		*data_error = -EILSEQ;
	else if (intmask & SDHCI_INT_DATA_TIMEOUT)
		if (!mmc_op_tuning(host->cmd->opcode))
			sdhci_err_stats_inc(host, DAT_CRC);
	} else if (intmask & SDHCI_INT_DATA_TIMEOUT) {
		*data_error = -ETIMEDOUT;
	else if (intmask & SDHCI_INT_ADMA_ERROR)
		sdhci_err_stats_inc(host, DAT_TIMEOUT);
	} else if (intmask & SDHCI_INT_ADMA_ERROR) {
		*data_error = -EIO;
	else
		sdhci_err_stats_inc(host, ADMA);
	} else
		*data_error = 0;

	/* Clear selected interrupts. */
@@ -3934,6 +3962,7 @@ bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error,
		sdhci_writel(host, intmask, SDHCI_INT_STATUS);
		pr_err("%s: CQE: Unexpected interrupt 0x%08x.\n",
		       mmc_hostname(host->mmc), intmask);
		sdhci_err_stats_inc(host, UNEXPECTED_IRQ);
		sdhci_dumpregs(host);
	}

+3 −0
Original line number Diff line number Diff line
@@ -356,6 +356,9 @@ struct sdhci_adma2_64_desc {
 */
#define MMC_CMD_TRANSFER_TIME	(10 * NSEC_PER_MSEC) /* max 10 ms */

#define sdhci_err_stats_inc(host, err_name) \
	mmc_debugfs_err_stats_inc((host)->mmc, MMC_ERR_##err_name)

enum sdhci_cookie {
	COOKIE_UNMAPPED,
	COOKIE_PRE_MAPPED,	/* mapped by sdhci_pre_req() */
+6 −0
Original line number Diff line number Diff line
@@ -99,6 +99,12 @@ static inline bool mmc_op_multi(u32 opcode)
	       opcode == MMC_READ_MULTIPLE_BLOCK;
}

static inline bool mmc_op_tuning(u32 opcode)
{
	return opcode == MMC_SEND_TUNING_BLOCK ||
			opcode == MMC_SEND_TUNING_BLOCK_HS200;
}

/*
 * MMC_SWITCH argument format:
 *