mmc: sdhci: Check device state before starting a request

This patch checks the device state before starting a request.
It also prints out useful information in case of error
conditions.

Change-Id: Iaf87bb069c3ffb13c9b3f174c07c25d612bdcee9
Signed-off-by: Asutosh Das <asutoshd@codeaurora.org>
[venkatg@codeaurora.org: remove pm related stuff]
Signed-off-by: Venkat Gopalakrishnan <venkatg@codeaurora.org>
[subhashj@codeaurora.org: fixed merge conflicts]
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
This commit is contained in:
Asutosh Das 2013-03-20 22:53:40 +05:30 committed by Subhash Jadavani
parent f55253f3e8
commit a93eca74ce

View file

@ -79,60 +79,80 @@ static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
} }
#endif #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) 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)); 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_readl(host, SDHCI_DMA_ADDRESS),
sdhci_readw(host, SDHCI_HOST_VERSION)); 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_SIZE),
sdhci_readw(host, SDHCI_BLOCK_COUNT)); 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_readl(host, SDHCI_ARGUMENT),
sdhci_readw(host, SDHCI_TRANSFER_MODE)); 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_readl(host, SDHCI_PRESENT_STATE),
sdhci_readb(host, SDHCI_HOST_CONTROL)); 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_POWER_CONTROL),
sdhci_readb(host, SDHCI_BLOCK_GAP_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_readb(host, SDHCI_WAKE_UP_CONTROL),
sdhci_readw(host, SDHCI_CLOCK_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_readb(host, SDHCI_TIMEOUT_CONTROL),
sdhci_readl(host, SDHCI_INT_STATUS)); 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_INT_ENABLE),
sdhci_readl(host, SDHCI_SIGNAL_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_ACMD12_ERR),
sdhci_readw(host, SDHCI_SLOT_INT_STATUS)); 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),
sdhci_readl(host, SDHCI_CAPABILITIES_1)); 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_readw(host, SDHCI_COMMAND),
sdhci_readl(host, SDHCI_MAX_CURRENT)); 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)); sdhci_readw(host, SDHCI_HOST_CONTROL2));
if (host->flags & SDHCI_USE_ADMA) { if (host->flags & SDHCI_USE_ADMA) {
if (host->flags & SDHCI_USE_64_BIT_DMA) 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_ERROR),
readl(host->ioaddr + SDHCI_ADMA_ADDRESS_HI), readl(host->ioaddr + SDHCI_ADMA_ADDRESS_HI),
readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
else 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_ERROR),
readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); 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; 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) static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
{ {
struct sdhci_host *host; struct sdhci_host *host;
@ -1402,6 +1430,15 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
host = mmc_priv(mmc); host = mmc_priv(mmc);
sdhci_runtime_pm_get(host); 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 */ /* Firstly check card presence */
present = sdhci_do_get_cd(host); present = sdhci_do_get_cd(host);
@ -2348,6 +2385,11 @@ static void sdhci_timeout_timer(unsigned long data)
sdhci_dumpregs(host); sdhci_dumpregs(host);
if (host->data) { 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; host->data->error = -ETIMEDOUT;
sdhci_finish_data(host); sdhci_finish_data(host);
} else { } 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) static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
{ {
u32 command; u32 command;
bool pr_msg = false;
BUG_ON(intmask == 0); BUG_ON(intmask == 0);
/* CMD19 generates _only_ Buffer Read Ready interrupt */ /* 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) if (host->ops->adma_workaround)
host->ops->adma_workaround(host, intmask); 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); sdhci_finish_data(host);
else { } else {
if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
sdhci_transfer_pio(host); sdhci_transfer_pio(host);