summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/sdhci.c96
1 files changed, 77 insertions, 19 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 5adddc4b30ce..7c52867bc5c3 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -79,60 +79,80 @@ static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
}
#endif
+static void sdhci_dump_state(struct sdhci_host *host)
+{
+ struct mmc_host *mmc = host->mmc;
+
+ #ifdef CONFIG_MMC_CLKGATE
+ pr_info("%s: clk: %d clk-gated: %d claimer: %s pwr: %d\n",
+ mmc_hostname(mmc), host->clock, mmc->clk_gated,
+ mmc->claimer->comm, host->pwr);
+ #else
+ pr_info("%s: clk: %d claimer: %s pwr: %d\n",
+ mmc_hostname(mmc), host->clock,
+ mmc->claimer->comm, host->pwr);
+ #endif
+ pr_info("%s: rpmstatus[pltfm](runtime-suspend:usage_count:disable_depth)(%d:%d:%d)\n",
+ mmc_hostname(mmc), mmc->parent->power.runtime_status,
+ atomic_read(&mmc->parent->power.usage_count),
+ mmc->parent->power.disable_depth);
+}
+
static void sdhci_dumpregs(struct sdhci_host *host)
{
- pr_debug(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n",
+ pr_info(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n",
mmc_hostname(host->mmc));
- pr_debug(DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n",
+ pr_info(DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n",
sdhci_readl(host, SDHCI_DMA_ADDRESS),
sdhci_readw(host, SDHCI_HOST_VERSION));
- pr_debug(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n",
+ pr_info(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n",
sdhci_readw(host, SDHCI_BLOCK_SIZE),
sdhci_readw(host, SDHCI_BLOCK_COUNT));
- pr_debug(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
+ pr_info(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
sdhci_readl(host, SDHCI_ARGUMENT),
sdhci_readw(host, SDHCI_TRANSFER_MODE));
- pr_debug(DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n",
+ pr_info(DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n",
sdhci_readl(host, SDHCI_PRESENT_STATE),
sdhci_readb(host, SDHCI_HOST_CONTROL));
- pr_debug(DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n",
+ pr_info(DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n",
sdhci_readb(host, SDHCI_POWER_CONTROL),
sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL));
- pr_debug(DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n",
+ pr_info(DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n",
sdhci_readb(host, SDHCI_WAKE_UP_CONTROL),
sdhci_readw(host, SDHCI_CLOCK_CONTROL));
- pr_debug(DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n",
+ pr_info(DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n",
sdhci_readb(host, SDHCI_TIMEOUT_CONTROL),
sdhci_readl(host, SDHCI_INT_STATUS));
- pr_debug(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
+ pr_info(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
sdhci_readl(host, SDHCI_INT_ENABLE),
sdhci_readl(host, SDHCI_SIGNAL_ENABLE));
- pr_debug(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
+ pr_info(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
sdhci_readw(host, SDHCI_ACMD12_ERR),
sdhci_readw(host, SDHCI_SLOT_INT_STATUS));
- pr_debug(DRIVER_NAME ": Caps: 0x%08x | Caps_1: 0x%08x\n",
+ pr_info(DRIVER_NAME ": Caps: 0x%08x | Caps_1: 0x%08x\n",
sdhci_readl(host, SDHCI_CAPABILITIES),
sdhci_readl(host, SDHCI_CAPABILITIES_1));
- pr_debug(DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n",
+ pr_info(DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n",
sdhci_readw(host, SDHCI_COMMAND),
sdhci_readl(host, SDHCI_MAX_CURRENT));
- pr_debug(DRIVER_NAME ": Host ctl2: 0x%08x\n",
+ pr_info(DRIVER_NAME ": Host ctl2: 0x%08x\n",
sdhci_readw(host, SDHCI_HOST_CONTROL2));
if (host->flags & SDHCI_USE_ADMA) {
if (host->flags & SDHCI_USE_64_BIT_DMA)
- pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x\n",
+ pr_info(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x\n",
readl(host->ioaddr + SDHCI_ADMA_ERROR),
readl(host->ioaddr + SDHCI_ADMA_ADDRESS_HI),
readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
else
- pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
+ pr_info(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
readl(host->ioaddr + SDHCI_ADMA_ERROR),
readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
}
- pr_debug(DRIVER_NAME ": ===========================================\n");
+ sdhci_dump_state(host);
+ pr_info(DRIVER_NAME ": ===========================================\n");
}
/*****************************************************************************\
@@ -1393,6 +1413,14 @@ static int sdhci_disable(struct mmc_host *mmc)
return 0;
}
+static bool sdhci_check_state(struct sdhci_host *host)
+{
+ if (!host->clock || !host->pwr)
+ return true;
+ else
+ return false;
+}
+
static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct sdhci_host *host;
@@ -1402,6 +1430,15 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
host = mmc_priv(mmc);
sdhci_runtime_pm_get(host);
+ if (sdhci_check_state(host)) {
+ sdhci_dump_state(host);
+ WARN(1, "sdhci in bad state");
+ mrq->cmd->error = -EIO;
+ if (mrq->data)
+ mrq->data->error = -EIO;
+ tasklet_schedule(&host->finish_tasklet);
+ return;
+ }
/* Firstly check card presence */
present = sdhci_do_get_cd(host);
@@ -2348,6 +2385,11 @@ static void sdhci_timeout_timer(unsigned long data)
sdhci_dumpregs(host);
if (host->data) {
+ pr_info("%s: bytes to transfer: %d transferred: %d\n",
+ mmc_hostname(host->mmc),
+ (host->data->blksz * host->data->blocks),
+ (sdhci_readw(host, SDHCI_BLOCK_SIZE) & 0xFFF) *
+ sdhci_readw(host, SDHCI_BLOCK_COUNT));
host->data->error = -ETIMEDOUT;
sdhci_finish_data(host);
} else {
@@ -2482,6 +2524,7 @@ static void sdhci_adma_show_error(struct sdhci_host *host) { }
static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
{
u32 command;
+ bool pr_msg = false;
BUG_ON(intmask == 0);
/* CMD19 generates _only_ Buffer Read Ready interrupt */
@@ -2544,10 +2587,25 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
if (host->ops->adma_workaround)
host->ops->adma_workaround(host, intmask);
}
-
- if (host->data->error)
+ if (host->data->error) {
+ if ((intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT)) &&
+ (host->quirks2 & SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING)) {
+ 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 (pr_msg) {
+ pr_err("%s: data txfr (0x%08x) error: %d\n",
+ mmc_hostname(host->mmc), intmask,
+ host->data->error);
+ sdhci_dumpregs(host);
+ }
sdhci_finish_data(host);
- else {
+ } else {
if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
sdhci_transfer_pio(host);