diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index ad0b4b331811..27049955e774 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -43,6 +43,11 @@ #define MAX_TUNING_LOOP 40 +#if defined(CONFIG_SDC_QTI) +#define SDHCI_DBG_DUMP_RS_INTERVAL (10 * HZ) +#define SDHCI_DBG_DUMP_RS_BURST 2 +#endif + static unsigned int debug_quirks = 0; static unsigned int debug_quirks2; @@ -1486,6 +1491,10 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) timeout += 10 * HZ; sdhci_mod_timer(host, cmd->mrq, timeout); +#if defined(CONFIG_SDC_QTI) + if (cmd->data) + host->data_start_time = ktime_get(); +#endif sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); mmc_log_string(host->mmc, "updated ARGUMENT=0x%08x ARGUMENT_MODE=0x%08x COMMAND=0x%08x\n", @@ -3127,6 +3136,10 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) { u32 command; +#if defined(CONFIG_SDC_QTI) + bool pr_msg = false; +#endif + /* CMD19 generates _only_ Buffer Read Ready interrupt */ if (intmask & SDHCI_INT_DATA_AVAIL) { command = SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)); @@ -3217,9 +3230,41 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) host->ops->adma_workaround(host, intmask); } - if (host->data->error) + if (host->data->error) { +#if defined(CONFIG_SDC_QTI) + if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT + | SDHCI_INT_DATA_END_BIT)) { + command = SDHCI_GET_CMD(sdhci_readw(host, + SDHCI_COMMAND)); + if ((command != MMC_SEND_TUNING_BLOCK_HS200) && + (command != MMC_SEND_TUNING_BLOCK)) + pr_msg = true; + } else { + pr_msg = true; + } + + if (host->mmc->ops->get_cd && + !host->mmc->ops->get_cd(host->mmc)) { + pr_msg = false; + pr_err("%s: Got data error(%d) during card removal\n", + mmc_hostname(host->mmc), host->data->error); + } + + if (pr_msg && __ratelimit(&host->dbg_dump_rs)) { + pr_err("%s: data txfr (0x%08x) error: %d after %lld ms\n", + mmc_hostname(host->mmc), intmask, + host->data->error, ktime_to_ms(ktime_sub( + ktime_get(), host->data_start_time))); + mmc_log_string(host->mmc, + "data txfr (0x%08x) error: %d after %lld ms\n", + intmask, host->data->error, + ktime_to_ms(ktime_sub(ktime_get(), + host->data_start_time))); + sdhci_dumpregs(host); + } +#endif sdhci_finish_data(host); - else { + } else { if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) sdhci_transfer_pio(host); @@ -3830,6 +3875,11 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev, */ host->adma_table_cnt = SDHCI_MAX_SEGS * 2 + 1; +#if defined(CONFIG_SDC_QTI) + ratelimit_state_init(&host->dbg_dump_rs, SDHCI_DBG_DUMP_RS_INTERVAL, + SDHCI_DBG_DUMP_RS_BURST); +#endif + return host; } diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index af6071b1de3d..7b7fa18a7644 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -15,7 +15,7 @@ #include #include #include - +#include #include /* @@ -616,6 +616,10 @@ struct sdhci_host { u64 data_timeout; +#if defined(CONFIG_SDC_QTI) + ktime_t data_start_time; + struct ratelimit_state dbg_dump_rs; +#endif unsigned long private[0] ____cacheline_aligned; };