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:
parent
f55253f3e8
commit
a93eca74ce
1 changed files with 77 additions and 19 deletions
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue