Skip to content

Commit efe8f5c

Browse files
Shaik Sajida Bhanustorulf
authored andcommitted
mmc: sdhci: Capture eMMC and SD card errors
Add changes to capture eMMC and SD card errors. This is useful for debug and testing. Signed-off-by: Liangliang Lu <[email protected]> Signed-off-by: Sayali Lokhande <[email protected]> Signed-off-by: Bao D. Nguyen <[email protected]> Signed-off-by: Shaik Sajida Bhanu <[email protected]> Acked-by: Adrian Hunter <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Ulf Hansson <[email protected]>
1 parent 91f059c commit efe8f5c

File tree

3 files changed

+53
-15
lines changed

3 files changed

+53
-15
lines changed

drivers/mmc/host/sdhci.c

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ void sdhci_reset(struct sdhci_host *host, u8 mask)
224224
if (timedout) {
225225
pr_err("%s: Reset 0x%x never completed.\n",
226226
mmc_hostname(host->mmc), (int)mask);
227+
sdhci_err_stats_inc(host, CTRL_TIMEOUT);
227228
sdhci_dumpregs(host);
228229
return;
229230
}
@@ -1716,6 +1717,7 @@ static bool sdhci_send_command_retry(struct sdhci_host *host,
17161717
if (!timeout--) {
17171718
pr_err("%s: Controller never released inhibit bit(s).\n",
17181719
mmc_hostname(host->mmc));
1720+
sdhci_err_stats_inc(host, CTRL_TIMEOUT);
17191721
sdhci_dumpregs(host);
17201722
cmd->error = -EIO;
17211723
return false;
@@ -1965,6 +1967,7 @@ void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
19651967
if (timedout) {
19661968
pr_err("%s: Internal clock never stabilised.\n",
19671969
mmc_hostname(host->mmc));
1970+
sdhci_err_stats_inc(host, CTRL_TIMEOUT);
19681971
sdhci_dumpregs(host);
19691972
return;
19701973
}
@@ -1987,6 +1990,7 @@ void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
19871990
if (timedout) {
19881991
pr_err("%s: PLL clock never stabilised.\n",
19891992
mmc_hostname(host->mmc));
1993+
sdhci_err_stats_inc(host, CTRL_TIMEOUT);
19901994
sdhci_dumpregs(host);
19911995
return;
19921996
}
@@ -3161,6 +3165,7 @@ static void sdhci_timeout_timer(struct timer_list *t)
31613165
if (host->cmd && !sdhci_data_line_cmd(host->cmd)) {
31623166
pr_err("%s: Timeout waiting for hardware cmd interrupt.\n",
31633167
mmc_hostname(host->mmc));
3168+
sdhci_err_stats_inc(host, REQ_TIMEOUT);
31643169
sdhci_dumpregs(host);
31653170

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

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

32413248
if (intmask & (SDHCI_INT_TIMEOUT | SDHCI_INT_CRC |
32423249
SDHCI_INT_END_BIT | SDHCI_INT_INDEX)) {
3243-
if (intmask & SDHCI_INT_TIMEOUT)
3250+
if (intmask & SDHCI_INT_TIMEOUT) {
32443251
host->cmd->error = -ETIMEDOUT;
3245-
else
3252+
sdhci_err_stats_inc(host, CMD_TIMEOUT);
3253+
} else {
32463254
host->cmd->error = -EILSEQ;
3247-
3255+
if (!mmc_op_tuning(host->cmd->opcode))
3256+
sdhci_err_stats_inc(host, CMD_CRC);
3257+
}
32483258
/* Treat data command CRC error the same as data CRC error */
32493259
if (host->cmd->data &&
32503260
(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)
32663276
-ETIMEDOUT :
32673277
-EILSEQ;
32683278

3279+
sdhci_err_stats_inc(host, AUTO_CMD);
3280+
32693281
if (sdhci_auto_cmd23(host, mrq)) {
32703282
mrq->sbc->error = err;
32713283
__sdhci_finish_mrq(host, mrq);
@@ -3342,6 +3354,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
33423354
if (intmask & SDHCI_INT_DATA_TIMEOUT) {
33433355
host->data_cmd = NULL;
33443356
data_cmd->error = -ETIMEDOUT;
3357+
sdhci_err_stats_inc(host, CMD_TIMEOUT);
33453358
__sdhci_finish_mrq(host, data_cmd->mrq);
33463359
return;
33473360
}
@@ -3370,23 +3383,30 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
33703383

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

33753389
return;
33763390
}
33773391

3378-
if (intmask & SDHCI_INT_DATA_TIMEOUT)
3392+
if (intmask & SDHCI_INT_DATA_TIMEOUT) {
33793393
host->data->error = -ETIMEDOUT;
3380-
else if (intmask & SDHCI_INT_DATA_END_BIT)
3394+
sdhci_err_stats_inc(host, DAT_TIMEOUT);
3395+
} else if (intmask & SDHCI_INT_DATA_END_BIT) {
33813396
host->data->error = -EILSEQ;
3382-
else if ((intmask & SDHCI_INT_DATA_CRC) &&
3397+
if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
3398+
sdhci_err_stats_inc(host, DAT_CRC);
3399+
} else if ((intmask & SDHCI_INT_DATA_CRC) &&
33833400
SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))
3384-
!= MMC_BUS_TEST_R)
3401+
!= MMC_BUS_TEST_R) {
33853402
host->data->error = -EILSEQ;
3386-
else if (intmask & SDHCI_INT_ADMA_ERROR) {
3403+
if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
3404+
sdhci_err_stats_inc(host, DAT_CRC);
3405+
} else if (intmask & SDHCI_INT_ADMA_ERROR) {
33873406
pr_err("%s: ADMA error: 0x%08x\n", mmc_hostname(host->mmc),
33883407
intmask);
33893408
sdhci_adma_show_error(host);
3409+
sdhci_err_stats_inc(host, ADMA);
33903410
host->data->error = -EIO;
33913411
if (host->ops->adma_workaround)
33923412
host->ops->adma_workaround(host, intmask);
@@ -3584,6 +3604,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
35843604
if (unexpected) {
35853605
pr_err("%s: Unexpected interrupt 0x%08x.\n",
35863606
mmc_hostname(host->mmc), unexpected);
3607+
sdhci_err_stats_inc(host, UNEXPECTED_IRQ);
35873608
sdhci_dumpregs(host);
35883609
}
35893610

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

3908-
if (intmask & (SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC))
3929+
if (intmask & (SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC)) {
39093930
*cmd_error = -EILSEQ;
3910-
else if (intmask & SDHCI_INT_TIMEOUT)
3931+
if (!mmc_op_tuning(host->cmd->opcode))
3932+
sdhci_err_stats_inc(host, CMD_CRC);
3933+
} else if (intmask & SDHCI_INT_TIMEOUT) {
39113934
*cmd_error = -ETIMEDOUT;
3912-
else
3935+
sdhci_err_stats_inc(host, CMD_TIMEOUT);
3936+
} else
39133937
*cmd_error = 0;
39143938

3915-
if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC))
3939+
if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC)) {
39163940
*data_error = -EILSEQ;
3917-
else if (intmask & SDHCI_INT_DATA_TIMEOUT)
3941+
if (!mmc_op_tuning(host->cmd->opcode))
3942+
sdhci_err_stats_inc(host, DAT_CRC);
3943+
} else if (intmask & SDHCI_INT_DATA_TIMEOUT) {
39183944
*data_error = -ETIMEDOUT;
3919-
else if (intmask & SDHCI_INT_ADMA_ERROR)
3945+
sdhci_err_stats_inc(host, DAT_TIMEOUT);
3946+
} else if (intmask & SDHCI_INT_ADMA_ERROR) {
39203947
*data_error = -EIO;
3921-
else
3948+
sdhci_err_stats_inc(host, ADMA);
3949+
} else
39223950
*data_error = 0;
39233951

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

drivers/mmc/host/sdhci.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,9 @@ struct sdhci_adma2_64_desc {
356356
*/
357357
#define MMC_CMD_TRANSFER_TIME (10 * NSEC_PER_MSEC) /* max 10 ms */
358358

359+
#define sdhci_err_stats_inc(host, err_name) \
360+
mmc_debugfs_err_stats_inc((host)->mmc, MMC_ERR_##err_name)
361+
359362
enum sdhci_cookie {
360363
COOKIE_UNMAPPED,
361364
COOKIE_PRE_MAPPED, /* mapped by sdhci_pre_req() */

include/linux/mmc/mmc.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ static inline bool mmc_op_multi(u32 opcode)
9999
opcode == MMC_READ_MULTIPLE_BLOCK;
100100
}
101101

102+
static inline bool mmc_op_tuning(u32 opcode)
103+
{
104+
return opcode == MMC_SEND_TUNING_BLOCK ||
105+
opcode == MMC_SEND_TUNING_BLOCK_HS200;
106+
}
107+
102108
/*
103109
* MMC_SWITCH argument format:
104110
*

0 commit comments

Comments
 (0)