Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 494003b1 authored by Asutosh Das's avatar Asutosh Das Committed by Xiaonian Wang
Browse files

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: default avatarAsutosh Das <asutoshd@codeaurora.org>
[venkatg@codeaurora.org: remove pm related stuff]
Signed-off-by: default avatarVenkat Gopalakrishnan <venkatg@codeaurora.org>
[subhashj@codeaurora.org: fixed merge conflicts]
Signed-off-by: default avatarSubhash Jadavani <subhashj@codeaurora.org>
[xiaonian@codeaurora.org: fix trivial merge conflict]
Signed-off-by: default avatarXiaonian Wang <xiaonian@codeaurora.org>
parent 270580a6
Loading
Loading
Loading
Loading
+78 −20
Original line number Diff line number Diff line
@@ -47,60 +47,80 @@ static void sdhci_finish_data(struct sdhci_host *);

static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);

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_err(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n",
	pr_info(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n",
		mmc_hostname(host->mmc));

	pr_err(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_err(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_err(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_err(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_err(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_err(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_err(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_err(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_err(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_err(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_err(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_err(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_err(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_err(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_err(DRIVER_NAME ": ===========================================\n");
	sdhci_dump_state(host);
	pr_info(DRIVER_NAME ": ===========================================\n");
}

/*****************************************************************************\
@@ -1520,6 +1540,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;
@@ -1528,6 +1556,16 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)

	host = mmc_priv(mmc);

	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 = mmc->ops->get_cd(mmc);

@@ -2474,6 +2512,11 @@ static void sdhci_timeout_data_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 if (host->data_cmd) {
@@ -2579,6 +2622,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;

	/* CMD19 generates _only_ Buffer Read Ready interrupt */
	if (intmask & SDHCI_INT_DATA_AVAIL) {
@@ -2651,10 +2695,24 @@ 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)) {
			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);